DEV Community

Cover image for Common Pitfalls: Code Practices That Disable Tree Shaking in Vue.js
Rafa Rafael
Rafa Rafael

Posted on

Common Pitfalls: Code Practices That Disable Tree Shaking in Vue.js

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 atOptimizing Vue.js Performance: A Guide to Tree Shaking with Webpack and Vite.

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:

const { calculateTax } = require('./utils/tax');
Enter fullscreen mode Exit fullscreen mode

The CommonJS require syntax is not statically analyzable by tree shaking tools.

Tree-Shakable Fix:

import { calculateTax } from './utils/tax';
Enter fullscreen mode Exit fullscreen mode

The ES2015 import syntax allows Webpack and Vite to analyze and eliminate unused exports.

2. Eliminating Side Effects

Non-Tree-Shakable Code:

export const pi = 3.14159;
console.log('Imported math utils!');
Enter fullscreen mode Exit fullscreen mode

Console logs and other side effects prevent tree shaking by indicating potential runtime changes.

Tree-Shakable Fix:

export const pi = 3.14159;
Enter fullscreen mode Exit fullscreen mode

Removing the console log ensures the module remains pure, enabling tree shaking.

3. Precise Dynamic Imports

Non-Tree-Shakable Code:

const models = require.context('./models', false, /\.js$/);
Enter fullscreen mode Exit fullscreen mode

Wildcard dynamic imports can include more than needed, making it hard for tree shaking to work.

Tree-Shakable Fix:

const UserModel = () => import('./models/UserModel');
Enter fullscreen mode Exit fullscreen mode

Explicit dynamic imports allow for more efficient code splitting and tree shaking.

4. Modular Library Importing

Non-Tree-Shakable Code:

import _ from 'lodash';
Enter fullscreen mode Exit fullscreen mode

Importing the entire library when only a fraction is needed bloats the bundle.

Tree-Shakable Fix:

import { cloneDeep } from 'lodash';
Enter fullscreen mode Exit fullscreen mode

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:

"sideEffects": false
Enter fullscreen mode Exit fullscreen mode

Incorrectly marking modules as side-effect-free when they aren't can lead to runtime issues.

Tree-Shakable package.json:

"sideEffects": ["*.vue", "*.css"]
Enter fullscreen mode Exit fullscreen mode

Precisely specify which files have side effects to guide the tree shaking process.

Vue.js Component Example: Optimal Import Usage

Non-Tree-Shakable Component:

const moment = require('moment');
Enter fullscreen mode Exit fullscreen mode

Using Moment.js with require pulls in the whole library, which is large and not tree-shakable.

Tree-Shakable Component:

import { format } from 'date-fns';
Enter fullscreen mode Exit fullscreen mode

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:

<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>
Enter fullscreen mode Exit fullscreen mode

Tree-Shakable Component Code:

<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>
Enter fullscreen mode Exit fullscreen mode

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!

Top comments (0)