question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Tree shaking doesn't work with Typescript barrel files

See original GitHub issue

Bug report

I originally raised this as a discussion, but now I think it’s a bug.

Describe the bug

When using a barrel file to re-export components from a single location, tree-shaking does not function correctly.

To Reproduce

I’m using Next 9.3.6 and I’ve arranged my components like:

  components/
    Header/
      Header.tsx
    Sidebar/
      Sidebar.tsx
    index.ts

Each component file exports a single component, like this:

export { Header }

index.ts is a barrel file that re-exports from each individual component file:

  export * from './Header/Header.tsx'
  export * from './Sidebar/Sidebar.tsx'
  // ...

I then use a couple of components in _app.tsx like:

import { Header, Sidebar } from "../components"

There’s about 100 components defined, and only a couple are used in _app.tsx. But when I analyze the bundle I have a very large chunk, shared by all pages, and it contains all my components, resulting in an inflated app page size:

Screenshot 2020-05-06 09 35 32

I use a similar import strategy within pages, and every one of them appears to contain every component.

my tsconfig.json is:

  "compilerOptions": {
    "allowJs": true,
    "baseUrl": ".",
    "forceConsistentCasingInFileNames": true,
    "esModuleInterop": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "lib": ["dom", "dom.iterable", "esnext"],
    "module": "esnext",
    "moduleResolution": "node",
    "noEmit": true,
    "noFallthroughCasesInSwitch": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "preserveConstEnums": true,
    "removeComments": false,
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "strict": true,
    "target": "es5"
  }

and I’m using next’s native support for the baseUrl field. I haven’t changed the module or the target.

When I change the _app.tsx imports to:

import { Header } from "../components/Header/Header"
import { Sidebar } from "../components/Sidebar/Sidebar"

the common bundle and app page size drops dramatically, as I would expect it to:

Screenshot 2020-05-06 09 34 21

Expected behavior

The app page size should be the same using both import strategies.

System information

  • OS: [e.g. macOS]
  • Version of Typescript: [e.g. 3.8.3]
  • Version of Next.js: [e.g. 9.3.6]

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:101
  • Comments:48 (4 by maintainers)

github_iconTop GitHub Comments

37reactions
yuchantcommented, Dec 15, 2021

Disabling side effects for my imported barrel libs works for me.

I don’t use side effects, seems like a lib thing to rely on that. Unless i’m sorely mistaken about side effects.

 webpack: (config, { dev }) => {
        config.module.rules = [
            ...config.module.rules,
            // ensure our libs barrel files don't constitute imports
            {
                test: /libs\/.*src\/index.ts/i,
                sideEffects: false,
            },
        ]
22reactions
yuchantcommented, Nov 9, 2022

I am curious as to why people use barrel files. I feel like it’s just adding an extra file that has a non-informational name to your project, and often complicates keyboard navigation (open definition, find file). The big advantage is making imports prettier? I spend very little time looking at imports.

Is there a benefit I’m missing on this or is it really about reducing lines of code in the import block?

Barrel files are effectively an API. A specific interface that distinguishes private vs public code. It especially makes sense in a monorepo with local packages. The same concept (why do packages have a specific import interface) pros/cons applies to monorepo packages. Being in the package mindset is helpful in its own right re; reusability/scalability too.

My opinion: barrels are annoying (having to create them, maintain them, deal with circular imports), but denoting public vs private code is helpful in maintenance just like private and public class methods.

Less refactoring required when files change; only the “API” (barrel file) needs to be updated.

Hides implementation from consumers.

Clear what changes are necessary if anything in public API changes, or if nothing in public API changes.

Arbitrary files imported by arbitrary other files is harder to maintain and understand than a single barrel. The possible scope of any modification is larger without barrels.

Ultimately, we all use barrels, via libraries. The same reasoning “why do libraries not just expose all file paths” applies to our own code as well.

There are cons, but that’s not your question. Those are just my 2cents that come to mind right now.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Barrel file and Tree Shaking - webpack - Stack Overflow
Move from webpack to rollup . Rollup has first-class tree shaking by default (I don't recommend to do it for large projects).
Read more >
Joe Bell on Twitter: "Use TypeScript barrel files in @nextjs ...
Tree shaking doesn't work with Typescript barrel files · Issue #12557 ... a barrel file to re-export components from a single location, tree-shaking...
Read more >
Tree-Shaking: A Reference Guide - Smashing Magazine
“Tree-shaking” is a must-have performance optimization when bundling JavaScript. In this article, we dive deeper on how exactly it works and ...
Read more >
Tree Shaking - webpack
ModuleConcatenationPlugin is needed for the tree shaking to work. It is added by mode: 'production' . If you are not using it, remember...
Read more >
How to add Barrels in TypeScript (or JavaScript)
Import all the interfaces and then export them in the same file. ... This barrel approach doesn't resolve a huge problem, but ovoid...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found