This is a small example repo on how to bundle a ESM library using webpack5. It was based on this blog post and the webpack documentation. It contains several branches:
- no-webpack: A ESM library setup without using webpack.
- webpack-react: A ESM library setup that uses Webpack and babel to bundle react components
- webpack-react-css: Similar to the branch above but now we also style the React component using Sass files.
- webpack-react-css-lodash-external: Similar to the branch but now we specify lodash as a external dependency.
- webpack-react-css-lodash-external-bundle-analyzer: Similar to the branch but now we also included a way to inspect the bundle using the webpack-bundle-analyzer.
- webpack-react-dev-server: Same as
webpack-react
but now also includes the use of the webpack dev server. - webpack-react-jsx-transform: Similar to above but now we use the new jsx-transform.
- webpack-react-jsx-transform-ejected: Similar to above but now we use also ejected the demo project.
- webpack-react-ts: Similar to
webpack-react
but now the js code has been converted to ts.
-
Pick a branch.
-
Install the node dependencies
npm i
. -
Build the bundle using webpack
npm run build
. -
Execute the
local_importer.js
node scriptnode local_importer.js
to see test that the bundle can be imported from inside the main package. -
Go into the CRA demo project. Currently the
webpack5-library-example
library is dynamically linked inside thepackage.json
. You can, however, also use the npm link command. -
Install the node dependencies.
-
Start the development server using
npm start
.
The steps below are taken from https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c:
-
Add
"type": "module"
to yourpackage.json
. -
Replace
"main": "index.js"
with"exports": "./index.js"
in your package.json. -
Update the
"engines"
field inpackage.json
toNode.js 12: "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
. -
Remove
'use strict';
from all JavaScript files. -
Replace all
require()/module.export
withimport/export
. -
Use only full relative file paths for imports:
import x from '.';
→import x from './index.js';
. -
If you have a TypeScript type definition (for example,
index.d.ts
), update it to use ESM imports/exports. -
Optional but recommended, use the node: protocol for imports.
-
Convert your
webpack.config.js
to a ESM module. -
Enable the experiments.outputModule option to make sure webpack outputs ECMASCript module syntax when possible.
-
Enable output.module to make sure that javascript files are outputted as ESM modules.
-
If you want your library to be consumed by others make sure to set the output.library.type flag to
module
. -
Point the
package.json
exports
property to your outputted bundle. -
If you want your ESM library to work with a CRA app you have to also specify the
"browser": "./build/index.js",
entry in yourpackage.json
. One known issue is #10933.
To see the example checkout the webpack-react-css-lodash-external branch. A guide on how to add externals can be found in the Webpack documentation. The only thing that you have to keep in mind is that when bundling a ES module the externalstype option is set to 'module'
by default. If your external module therefore is a ESM module you simply use the following:
externals: {
"lodash-es": "lodash-es",
}
If your external module is specified in a different format see the documentation.