Using Code Splitting on a Component Library built with Webpack

271 Views Asked by At

I have a component library that is published to npm, and installed in other projects.

The library doesn't use dynamic imports. The components are exported in the library as follows:

import {
  Component1
} from '@/modules/component1';

import {
  Component2
} from '@/modules/component2';

import {
  Component3
} from '@/modules/component3';

export {
  Component1,
  Component2,
  Component3,
};

the components are imported as follows:

import {Component1, Component2} from 'myLibrary';

When building the component library, without any code splitting, it works properly, but the whole library is imported and affects the size of the page.

When using webpack's splitChunks the main entry point of the library doesn't export the components, and exports show as undefined.

As I understood splitChunks works best in scenarios when using it with HtmlWebpackPlugin to add script tags for all the chunks. This doesn't work in my case since I am building it as a library.

Also, I tried building each component as an entry point separately, but the files were still too big. When I used splitChunks the file sizes were very convenient, but the components were not exported.

How should I achieve this? I want to split the library into multiple files but still being able to import it in my code and access all the exported components.

Note: The main goal of this is to reduce file size, this is bundled into a browser extension so network performance doesn't matter since the files are available offline.

1

There are 1 best solutions below

0
On

While it's hard to give more concrete advice without seeing your library and how you bundle it. But usually, you don't want to do much of bundling and lazy loading on the library itself. Ideally, it should be just tree-shakable. What it means is bundler (webpack in your case) will include in final bundle only parts of library which you use in app. So if you import only Component2 in your app, webpack will include only Component2 itself and parts required for it to work (but not Component1 or Component3). For your library to support this you need to do a bit of extra work. Webpack has guide about tree shaking which will be good starting point. I would also recommend to read about ESM vs CommonJS (for example this article) and make sure that webpack compiles your library into separate ESM files.

And later in the app (browser extension in your case) you can optimize code splitting. This can be in for of pre-defined code chunks. For example, you could split your code in pre-defined ui.js (all ui related code like components) and libs.js (all other used libraries) chunks and then load only chunks you need (e.g. ui.js won't be needed in background worker so no need to load it there). I used this approach for some time in my browser extension template, you can find example here.

Alternatively, with a bit of tweaking webpack configuration you can make import() function work in extension context. In this case webpack will automatically optimize chunks so every entrypoint (popup / contentscript / background worker) will load a minimal amount of unnecessary code. I currently use this approach in my projects and very satisfied with the results (though it might not work in older browsers). You can find example configuration here or check this plugin.

As additional bonus, you will be able to use dynamic import in your code, which allows you to lazy load parts of extension (though this will require adapting your app a bit) which also will reduce size of initial bundle.