14

I am trying to create a component library wie rollup and Vue that can be tree shakable when others import it. My setup goes as follows:

Relevant excerpt from package.json

{
  "name": "red-components-with-rollup",
  "version": "1.0.0",
  "sideEffects": false,
  "main": "dist/lib.cjs.js",
  "module": "dist/lib.esm.js",
  "browser": "dist/lib.umd.js",
  "scripts": {
    "build": "rollup -c",
    "dev": "rollup -c -w"
  },
  "devDependencies": {
    /* ... */
}

And this is my entire rollup.config.js

import resolve from "rollup-plugin-node-resolve";
import commonjs from "rollup-plugin-commonjs";
import vue from "rollup-plugin-vue";
import pkg from "./package.json";

export default {
  input: "lib/index.js",
  output: [
    {
      file: pkg.browser,
      format: "umd",
      name: "red-components"
    },
    { file: pkg.main, format: "cjs" },
    { file: pkg.module, format: "es" }
  ],
  plugins: [resolve(), commonjs(), vue()]
};

I have a fairly simple project structure with an index.js file and 2 Vue components:

root
 ∟ lib
    ∟ index.js
    ∟ components
       ∟ Anchor.vue
       ∟ Button.vue
 ∟ package.json
 ∟ rollup.config.js

My index.js imports the Vue files and exports them:

export { default as Anchor } from "./components/Anchor.vue";
export { default as Button } from "./components/Button.vue";

export default undefined;

If I don't do export default undefined; somehow any app importing my library cannot find any exports. Weird.


Now when I create another app and I import red-components-with-rollup like so:

import { Anchor } from "red-components-with-rollup";

and I open the bundle from my app, I will also find the source code of the Button.vue in my bundle, it has not been eliminated as dead code.

What am I doing wrong?

Lukas
  • 9,752
  • 15
  • 76
  • 120
  • i believe that each export should be in a Separate File, so that your import looks like: `import Anchor from "red-components-with-rollup/Anchor";` – Sebastian Scholle Nov 14 '19 at 14:51

2 Answers2

2

What is the build result of the ES format? Is it a single file or multiples, similar to your sources?

Considering your Rollup options, I’m guessing it bundles everything into a single file, which is most probably the reason it isn’t able to tree-shake it.

To keep your ES build into multiple files, you should change:

{ file: pkg.module, format: "es" }

Into:

{
  format: "es",
  // Use a directory instead of a file as it will output multiple
  dir: 'dist/esm'
  // Keep a separate file for each module
  preserveModules: true,
  // Optionally strip useless path from source
  preserveModulesRoot: 'lib',
}

You’ll need to update your package.json to point module to the new build file, something like "module": "dist/esm/index.js".

LeBen
  • 1,884
  • 12
  • 21
-1

There are some interesting pitfalls with tree shaking that this article covers that you might be interested in.

Other than that - does your build tooling for your consumer app support pure es modules and have tree shaking capabilities? If so, then i would just make sure your exported files are not doing any 'side-effecty' things that might confuse rollup.

To be on the safe side i would offer direct imports to for each of your components as well as one main index.js that exports them. At least you're giving people who are paranoid of shipping unused code the option ie -

import { Anchor } from "red-components-with-rollup/Anchor";

Samuel
  • 2,485
  • 5
  • 30
  • 40
  • I’ve seen this practice, but never understood how to accomplish it. Any chance you can explain how to configure a lib so it can have both export methods? – ericchernuka Oct 22 '21 at 12:10