Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you make a library truly tree-shakable with webpack?

I have a library of multiple react components, and I want to make the library tree-shakable so that when I import a component like

import { Checkbox } from 'my-react-components'

I don't import the whole bundle.

My index.js looks like this

export { default as Button } from './components/Button'
export { default as Checkbox } from './components/Checkbox'
export { default as FlexView } from './components/FlexView'
export { default as Radio } from './components/Radio'
export { default as Select } from './components/Select'
export { default as TextInput } from './components/TextInput'
export { default as Toggle } from './components/Toggle'

And I bundle using webpack

module.exports = {
  mode: 'production',
  entry: './src/index.ts',
  output: {
    path: path.resolve('./lib'),
    filename: 'react-components.js',
    libraryTarget: 'commonjs2',
  },

  // loaders and stuff...
  // terser-webpack-plugin...

  externals: {
    // don't include react in the bundle
    react: {
      root: 'React',
      commonjs2: 'react',
      commonjs: 'react',
      amd: 'react',
    },
  },
  optimization: {
    splitChunks: false,
    sideEffects: false,
  },
}

And in my babel config of course I have

['@babel/preset-env', {
  modules: false,
}]

With this setup when I import only one component, and the whole bundle gets included (I am using webpack also when I import it). How do I prevent this?

like image 389
Pontiacks Avatar asked Dec 06 '18 13:12

Pontiacks


People also ask

Does webpack have tree shaking?

In webpack, tree shaking works with both ECMAScript modules (ESM) and CommonJS, but it does not work with Asynchronous Module Definition (AMD) or Universal Module Definition (UMD).

How webpack detect the dead code that can help in tree shaking?

It relies on the import and export statements to detect if code modules are exported and imported for use between JavaScript files. In modern JavaScript applications, we use module bundlers (e.g., webpack or Rollup) to automatically remove dead code when bundling multiple JavaScript files into single files.


2 Answers

As of February 2020 it is not possible with Webpack.

Because tree-shaking mechanism heavily relies on ES6 import/export and Webpack currently doesn't support ES2015 module format in output.libraryTarget.

As an alternative you can bundle your library with other bundlers like Rollup (which does support ES6 modules for libraries).

You can keep track of this feature here: https://github.com/webpack/webpack/issues/2933

UPDATE: Though there is hacky workaround: https://stackoverflow.com/a/60010871/921193

like image 167
WelcomeTo Avatar answered Oct 03 '22 15:10

WelcomeTo


I believe you also need the module property on your package.json

{
   ...
   "main": "lib/index.js",
   "module": "lib/index.esm.js",
   ...
}
like image 35
Alejandro Garcia Anglada Avatar answered Oct 03 '22 13:10

Alejandro Garcia Anglada