This is the second article in the series of me optimizing the performance of a React webapp.
For better context, the React app being mentioned is part of a large monorepo, in which there is a packages/ui
, which contains all the UI components consumed by /apps/*
. I couldn't help but notice almost every modules from packages/ui
were being pulled into the final bundle. Despite my effort to remove circular dependencies & barrel files. As a result, the index.js file which contains our business-logic code weights about 1.5MB un-compressed:
build/assets/index.cbcdbec4.js 1566.62 KiB
I spent weeks outside of working hour to find a way to fix it. And by pure coincidence, I came across a comment on Reddit mentioning sideEffect
and how it helped reduce the bundle size of their Next.js app (yes I confess I have not heard about sideEffects
until then). The change took just one line of code, inside the package.json
file of packages/ui
:
{ ..., "sideEffects": false }
And the result, to my utmost surprise, is a ~70% reduction in the size of the mentioned index.js file:
build/assets/index.a98b35bf.js 501.31 KiB
This 1-LOC-change is by far the most low-effort-high-impact pull request that I have done in my entire career working on web applications. However it's worth mentioning that setting sideEffects
to false does not come without, well, side effects. Setting the value to false means, in our case, Vite will drop all the top-level functions like css imports and functions that run immediately after they are imported. To circumvent, you could declare the paths that DO have side effects, so that Vite knows to include them in the final bundle.
{ ..., "sideEffects": ["**/*.css", "**/side-effect-module.ts"] }
import top from '@ericcornelissen/eslint-plugin-top'; import tsParser from '@typescript-eslint/parser'; /** @type {import("eslint").FlatConfig[]} */ export default [ { ignores: ['**/node_modules/**', '**/dist/**', "**/*.test.tsx", "**/*.test.ts"], }, { files: ['packages/ui/**/*.{ts,tsx}'], languageOptions: { parser: tsParser, sourceType: 'module', ecmaVersion: 'latest', }, plugins: { top: top, }, rules: { 'top/no-top-level-side-effects': 'error', 'top/no-top-level-variables': 'error' } }, ];