Common Pitfalls: Code Practices That Disable Tree Shaking in Vue.js
Tags: vue, javascript, tutorial
Published: 2023-11-09 16:00:00

In my last guide, I detailed the implementation of tree shaking to streamline Vue.js applications by pruning unnecessary code from your bundles with Vite or Webpack. You can explore it at[Optimizing Vue.js Performance: A Guide to Tree Shaking with Webpack and Vite](https://dev.to/rafaelogic/optimizing-vuejs-performance-a-guide-to-tree-shaking-with-webpack-and-vite-3if7).

Now, I am going to take a more clarity dive as I'll walk you through some common coding practices that could disable tree shaking, specifically in the context of Vue.js applications using Webpack and Vite. It's crucial to not only understand how to enable tree shaking but also to recognize what could inadvertently prevent it from working correctly.

In my experience with Webpack and Vite, I've encountered several instances where certain coding patterns led to bloated bundles, negating the benefits of tree shaking. Let's explore these patterns and learn how to avoid them, ensuring that we're fully leveraging the capabilities of our bundlers to produce lean and efficient applications.

Remember, the goal here is to make sure that every byte of JavaScript we serve to the client is essential. By being mindful of these potential pitfalls, we can keep our Vue.js apps as lightweight and performant as possible.

Now, let's look at some examples of code that you should avoid to ensure that tree shaking can do its job effectively.

**1. Using ES2015 Module Syntax**

*Non-Tree-Shakable Code:*
```javascript
const { calculateTax } = require('./utils/tax');
```
The CommonJS `require` syntax is not statically analyzable by tree shaking tools.

*Tree-Shakable Fix:*
```javascript
import { calculateTax } from './utils/tax';
```
The ES2015 `import` syntax allows Webpack and Vite to analyze and eliminate unused exports.

**2. Eliminating Side Effects**

*Non-Tree-Shakable Code:*
```javascript
export const pi = 3.14159;
console.log('Imported math utils!');
```
Console logs and other side effects prevent tree shaking by indicating potential runtime changes.

*Tree-Shakable Fix:*
```javascript
export const pi = 3.14159;
```
Removing the console log ensures the module remains pure, enabling tree shaking.

**3. Precise Dynamic Imports**

*Non-Tree-Shakable Code:*
```javascript
const models = require.context('./models', false, /\.js$/);
```
Wildcard dynamic imports can include more than needed, making it hard for tree shaking to work.

*Tree-Shakable Fix:*
```javascript
const UserModel = () => import('./models/UserModel');
```
Explicit dynamic imports allow for more efficient code splitting and tree shaking.

**4. Modular Library Importing**

*Non-Tree-Shakable Code:*
```javascript
import _ from 'lodash';
```
Importing the entire library when only a fraction is needed bloats the bundle.

*Tree-Shakable Fix:*
```javascript
import { cloneDeep } from 'lodash';
```
Importing only the necessary functions enables unused parts of the library to be shaken off.

**5. Accurate Side Effect Flagging**

*Non-Tree-Shakable `package.json`:*
```json
"sideEffects": false
```
Incorrectly marking modules as side-effect-free when they aren't can lead to runtime issues.

*Tree-Shakable `package.json`:*
```json
"sideEffects": ["*.vue", "*.css"]
```
Precisely specify which files have side effects to guide the tree shaking process.

**Vue.js Component Example: Optimal Import Usage**

*Non-Tree-Shakable Component:*
```javascript
const moment = require('moment');
```
Using Moment.js with `require` pulls in the whole library, which is large and not tree-shakable.

*Tree-Shakable Component:*
```javascript
import { format } from 'date-fns';
```
Using alternative package like `date-fns` that offers modular imports, so only the needed function is included, allowing for tree shaking.

Each fix contributes to a leaner, more efficient bundle by ensuring that the code is structured in a way that modern bundlers can optimize through tree shaking.

**Vue.js Component Example: Non-Tree-Shakable Code**

*Problematic Component Code:*
```javascript
<template>
  <div>
    <h1>Current Time</h1>
    <p>{{ currentTime }}</p>
  </div>
</template>

<script>
const moment = require('moment'); // Non-tree-shakable

export default {
  name: 'CurrentTime',
  data() {
    return {
      currentTime: moment().format('LLLL'), // Moment.js is a large library
    };
  },
};
</script>
```

*Tree-Shakable Component Code:*
```javascript
<template>
  <div>
    <h1>Current Time</h1>
    <p>{{ currentTime }}</p>
  </div>
</template>

<script>
// Use tree-shakable imports
import { format } from 'date-fns';

export default {
  name: 'CurrentTime',
  setup() {
    const currentTime = format(new Date(), 'LLLL'); // Using date-fns for its tree-shaking benefits

    return {
      currentTime
    };
  },
};
</script>
```

In the fixed component code, we've replaced Moment.js with `date-fns`, a library that's known for being modular and tree-shakable. We import only the `format` function that we need, rather than the whole library. This makes our component leaner and our final bundle smaller.

By applying these fixes, we ensure that our code is optimized for tree shaking, allowing Webpack and Vite to remove any unused code effectively, resulting in more efficient applications.

#### Enjoy!