Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move from webpack to esbuild bundler #1210

Merged
merged 1 commit into from
Mar 2, 2023

Conversation

martinpitt
Copy link
Member

@martinpitt martinpitt commented Feb 19, 2023

This speeds up the bundle build considerably, from about 26 s with
webpack to about 6s with esbuild.

Drop babel. esbuild understands JSX natively, and we don't need the
"transpile to ES5" any more -- all recent browsers understand ES6.

esbuild also creates LEGAL.txt files in development mode (unlike webpack
terser), so we can drop this hack as well.

Co-Authored-By: Martin Pitt mpitt@redhat.com

TODO:

All credit for this goes to @KKoukiou . I am mostly sending this PR to give it a trial run on CI, and collect a TODO list

Development: Cockpit now supports the esbuild bundler

esbuild is a much faster bundler alternative for webpack. It also natively understands JSX, so that it is not necessary any more to use babel. Cockpit's shared components and bundler plugins in pkg/lib/ now support both eslint and webpack, so that projects can pick either. cockpit-podman moved to esbuild in this commit. You may choose to do the same for your project.

@martinpitt
Copy link
Member Author

@KKoukiou : I updated esbuild-rsync-plugin.js here to be usable with webpack and esbuild. I tested the unchanged file with both bundlers, with and without $RSYNC. Next step is to do the same for the po plugin, then update both of them in cockpit, then we can use them from the shared code import. WDYT?

@garrett
Copy link
Member

garrett commented Feb 21, 2023

Note: Switching from our breakpoint SCSS import dance to rewriting the CSS breakpoints will help detangle our SCSS and will probably make it smaller in the resulting size too. And it'll also fix our breakpoints further (as it's still broken in some places). So it'd probably help here too.

Details @

@martinpitt
Copy link
Member Author

This branch is somehow out of date. But when I rebase to main and rebuild node_modules, the bundle sizes are now as we had with webpack. Amazing work! :clap 💯

@martinpitt
Copy link
Member Author

martinpitt commented Feb 23, 2023

@KKoukiou : So AFAICS: Land #1214 ✔️ , rebase/rebuild this ✔️ , add plugins to cockpit pkg/lib/, pull this in here, and collect trophy, right? 🏆

jelly
jelly previously approved these changes Feb 28, 2023
build.js Outdated Show resolved Hide resolved
@jelly
Copy link
Member

jelly commented Feb 28, 2023

The analyzer is cool:

image

image

Interesting... docker-names is 53 kB I guess it's all the comments which aren't getting stripped?

https://github.com/bearjaws/docker-names/blob/master/index.js#L141

Local changes. also requires some dropping of the npm run build output out of the logged json.

diff --git a/build.js b/build.js
index e8a6cec7..c0eb3512 100644
--- a/build.js
+++ b/build.js
@@ -31,6 +31,7 @@ const context = await esbuild.context({
     // show "build started/finished" messages in watch mode
     logLevel: 'info',
     minify: production,
+    metafile: true,
     nodePaths,
     outdir: "./dist",
     target: ['es2020'],
@@ -67,6 +68,6 @@ const context = await esbuild.context({
 if (watchMode)
     await context.watch();
 else {
-    await context.rebuild();
+    await context.rebuild().then(result => console.log(JSON.stringify(result.metafile)));
     context.dispose();
 }

@jelly
Copy link
Member

jelly commented Feb 28, 2023

I found one minor bug when I run NODE_ENV=production npm run build twice.

[jelle@t14s][~/projects/cockpit-podman]%NODE_ENV=production npm run build > metafile.json
node:internal/errors:867
  const err = new Error(message);
              ^

Error: Command failed: gzip -9 dist/po.ko.js
gzip: dist/po.ko.js.gz already exists;  not overwritten

    at ChildProcess.exithandler (node:child_process:419:12)
    at ChildProcess.emit (node:events:512:28)
    at maybeClose (node:internal/child_process:1098:16)
    at Socket.<anonymous> (node:internal/child_process:456:11)
    at Socket.emit (node:events:512:28)
    at Pipe.<anonymous> (node:net:316:12) {
  code: 2,
  killed: false,
  signal: null,
  cmd: 'gzip -9 dist/po.ko.js',
  stdout: '',
  stderr: 'gzip: dist/po.ko.js.gz already exists;\tnot overwritten\n'
}

@martinpitt
Copy link
Member Author

@jelly Thanks, well spotted! This needs to be fixed in the plugin in cockpit.git, I'm happy to do that.

jelly
jelly previously approved these changes Feb 28, 2023
@jelly
Copy link
Member

jelly commented Feb 28, 2023

Now with a production build!

image

KKoukiou
KKoukiou previously approved these changes Feb 28, 2023
@martinpitt
Copy link
Member Author

@jelly 's issue is actually much worse.. It also happens with NODE_ENV=production npm run watch on the second build.

These are both a symptom of a deeper problem: The dist/ directory does not get cleaned between the builds. Do this:

rm -rf dist; NODE_ENV=production npm run build; npm run build

Now dist/ has both the compressed (production) and uncompressed (devel) files. This has already annoyed me a lot with webpack, that does the same. So the use case is to start with a prod build (from e.g. make vm or make check), then wanting to fix something, running make watch and wondering why the changes don't apply -- it's because cockpit-ws prefers serving .gz files.

So we need to clean up old files, or possibly all files, in dist/ on each round. webpack has a clean: true option, we should check if esbuild has something similar, and if not, build it somehow.

@martinpitt
Copy link
Member Author

https://esbuild.github.io/api/#outdir documents this behaviour, and basically says "do it yourself". So I added a trivial cleanPlugin, all of the cases above work now (building twice, switching between prod and dev, watch mode). @KKoukiou , @jelly , PTAL?

@martinpitt martinpitt force-pushed the esbuild branch 2 times, most recently from 3a7a38e to c5a1c47 Compare March 1, 2023 08:59
@martinpitt
Copy link
Member Author

Wah, node_modules/ changes every two hours, rebuilt for the 128th time.

@martinpitt
Copy link
Member Author

martinpitt commented Mar 1, 2023

After some discussion with @KKoukiou , I cleaned up how we handle the linters. Pushing with an extra committ which should fail in CI. After this proves to works as intended, I'll take it out again.

Update: Failed as intended

This speeds up the bundle build considerably, from about 26 s with
webpack to about 6s with esbuild.

Drop babel. esbuild understands JSX natively, and we don't need the
"transpile to ES5" any more -- all recent browsers understand ES6.

esbuild also creates LEGAL.txt files in development mode (unlike webpack
terser), so we can drop this hack as well.

Also merge the ESLINT and STYLELINT env vars into a single LINT one, and
unify how we handle them. As they dominate the bundler time, let's make
sure the linters only run in CI and for watch mode, but not for
production builds.

Co-Authored-By: Martin Pitt <mpitt@redhat.com>
Comment on lines +21 to +22
// always start with a fresh dist/ directory, to change between development and production, or clean up gzipped files
const cleanPlugin = {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose this should also eventually move to cockpit's pkg/lib/, but at this point my gut feeling is that we can land this PR, and do that separately. @KKoukiou is already working on esbuild-ifying cockpit.git, and she will most certainly add the clean plugin there as well.

@martinpitt martinpitt merged commit d48f582 into cockpit-project:main Mar 2, 2023
@martinpitt martinpitt deleted the esbuild branch March 2, 2023 08:32
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.

None yet

4 participants