Skip to content

build: replace webpack with esbuild for the dist/ bundles - #2

Closed
tomalec wants to merge 6 commits into
fix/npm-auditfrom
build/esbuild
Closed

tomalec wants to merge 6 commits into
fix/npm-auditfrom
build/esbuild

Conversation

@tomalec

@tomalec tomalec commented Oct 27, 2026 •

Copy link
Copy Markdown
Owner

Stacked on fix/npm-audit

What

Bundles dist/ with esbuild instead of webpack, and drops webpack from the devDependencies.

The browser bundles keep the same shape as 3.1.1:

  • ES5 (--target=es5; esbuild refuses syntax it can't lower to ES5)
  • the jsonpatch global with the same 15 exports
  • the /*! fast-json-patch, version: … */ banner and both licence headers

The bytes change, so the next release ships different bundles. On a fresh build:

File webpack esbuild
dist/fast-json-patch.js 37 532 B 29 198 B
dist/fast-json-patch.min.js 12 805 B 12 266 B

dist/ is not part of this PR. It is committed only by the release build (npm version runs build).

Why

  • Webpack was the bulk of the dependency tree: package-lock.json goes from 202 to 104 entries (175 before esbuild is added), 26 of them esbuild's per-platform binaries. fast-uri goes with it; it was only there through webpack's ajv.
  • The build config is two package.json scripts (build-dist, bundle) instead of a config file. webpack.config.js is gone, so it is no longer in the published package (24 files → 23).

Commits

  1. test: smoke-test the browser bundles in dist/: npm run test-dist loads each bundle in a fresh global scope and checks the banner, the jsonpatch global against the exports of index.js, and one applied and one generated patch. CI runs it after test-browser, which builds dist/; the version script runs it before staging the release build.
  2. build: add esbuild as a devDependency
  3. test: bundle the import test with esbuild: replaces test-webpack-import with test-bundler-import, same assertions.
  4. build: bundle dist/ with esbuild
  5. build: drop webpack: also removes the stale webpack.config.js entry from bower.json and the webpack mentions in the tsconfig.json comments.

Things to know

  • esbuild is ^0.28.2: published with provenance, well past the 7-day min-release-age in .npmrc. Its install script is skipped by ignore-scripts; the platform binaries come from optional dependencies.
  • The banner reads the version from $npm_package_version, so building dist/ needs a POSIX shell (Linux, macOS, Git Bash, WSL). The old config read package.json in Node.
  • test-dist checks ES5 syntax through the build target, not runtime APIs (the bundle calls Object.assign, as the webpack one did).

How to check

npm ci
npm test
npm run build && npm run test-dist
git checkout -- dist   # the build rewrites the committed bundles
  • CI green (including test-browser on Chromium, Firefox and WebKit)

- `fast-uri` 3.1.8 -> 3.1.9 (via webpack's `ajv`): GHSA-w74x-v6f9-j3xg,
  GHSA-wjr9-j795-jxcr, GHSA-xhq7-xmqj-769h, GHSA-333x-w4r6-6crp.
- `qs` 6.16.0 -> 6.16.1 (via `http-server`): GHSA-6pq8-jhm2-2vcw.
The browser suite imports `index.mjs`, so nothing tested the bundles a
`<script>` tag loads, and the next release rebuilds them with webpack 5.
`npm run test-dist` loads each bundle in a fresh global scope and checks:
the version banner, the `jsonpatch` global with the same exports as
`index.js`, and one applied and one generated patch.

It passes on the 3.1.1 bundles and on a fresh build, and fails on a banner
left at an older version.

- CI runs it after `test-browser`, which builds `dist/`.
- The `version` script runs it before staging the release build.
esbuild replaces webpack for the `dist/` bundles and for the import test in
the next commits. 0.28.2 is published from GitHub Actions with a provenance
attestation.

- Its only install script is a `postinstall` that swaps a JS shim for the
  native binary. `ignore-scripts=true` in `.npmrc` skips it, and esbuild
  still works without it.
- The lockfile gets 26 optional `@esbuild/*` binaries, one per platform;
  npm installs only the one that matches.
`test-webpack-import` bundles `test/spec/webpack/importSpec.src.js` and
runs the result, so the `import` path of the package stays covered. Do the
same with esbuild, ahead of dropping webpack.

- `test-bundler-import`: replaces `test-webpack-import` and is called by
  `npm test`. `--main-fields=module,main` makes esbuild resolve `index.mjs`
  like webpack did for `target: node`.
- Move the spec to `test/spec/esbuild/` and say "esbuild" in its title.
- Stop tracking the build output: `importSpec.build.js` is now ignored
  instead of committed.
Replace webpack in `npm run build`. The flags live in `package.json`, so
there is no build config to maintain or to ship in the package.

- `bundle`: `index.js` as an IIFE that defines the global `jsonpatch`, ES5
  (`--target=es5`), with the `/*!` licence comments inline
  (`--legal-comments=inline`) and the `fast-json-patch, version: X` banner
  from `$npm_package_version`, so it needs a POSIX shell.
- `build-dist`: the plain and the minified bundle.
- Delete `webpack.config.js`. The package no longer ships it: 23 files
  instead of 24, none added.

`npm run test-dist` passes on the new output: ES5 syntax, the same 15
exports, the banner and the three `/*!` comments. The bundles get smaller,
as webpack's runtime is gone: 37.5 to 29.2 kB, minified 12.8 to 12.3 kB.
`dist/` itself is not rebuilt here; the release build does that.
Nothing uses it any more. Remove `webpack`, `webpack-cli` and
`minimizer-webpack-plugin` from the devDependencies.

`package-lock.json` drops from 202 to 104 entries (175 before esbuild), 26
of them esbuild's per-platform binaries. `fast-uri` goes too: it was only
there through webpack's `ajv`.

- `tsconfig.json` and `test/spec/typings/tsconfig.json`: drop "from webpack" from
  the comment on `"types": []`.
  No `@types/*` package is installed any more; the setting stays, so the
  `@types` of a future devDependency don't leak into the build.
- `bower.json`: drop `webpack.config.js` from `ignore`.
@tomalec

tomalec commented Oct 28, 2026

Copy link
Copy Markdown
Owner Author

Moved upstream: Starcounter-Jack#336

@tomalec tomalec closed this Oct 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant