Esbuild 0.9
github.com
github.com
For example, you can now speed up your Webpack build with esbuild by replacing babel-loader/ts-loader/Terser: https://github.com/privatenumber/esbuild-loader
(It also blows my mind that Evan is the CTO is Figma. How is he so productive!?)
arguably he's doing his job just working on this thing all by himself
When Evan first joined Figma, he saw how much time the engineers spent on waiting for webpack and fighting JS configuration files. Then one time, during an outage, the developers tried to push a fix but the build was failing because babel-deduplicate-int had changed their API interface but only did a minor version bump when published to NPM, and Figma engineers are at the edge of technology so they use version ranges, not fixed versions.
When Evan heard this he pored up some whisky and created esbuild in two nights. And the JS developers rejoiced. Now the developers were so productive, that Evan already had nothing to do. No one was fighting, all engineers were happy and playing ping-pong like any everyday was Friday.
So now the only thing keeping all the JS engineers happy at Figma, is the continued success and improvement of esbuild. So Evan just spends his time with esbuild now.
(This is all fictional, of course)
Haha, you really had me going with that first paragraph. Felt so real.
Edit: Kind of. It was really simple to switch over and build. But the optimizer example actually makes my output much larger than the webpack default settings. Also it can't seem to handle the "implicitly assume I have React in scope for each JSX file."
It felt maybe twice as fast, but not 10-100x to really game change my dev loop.
Our bundle got noticeably smaller, but we chalked that up to esbuild not polyfilling for as early a target as we had been with babel-loader.
esbuild App.tsx --define:process.env.NODE_ENV=\\\"production\\\" --bundle --minify --target=es6 --outfile=out.js
where App.tsx is your entry point. Include out.js into the page and you're done.[0] https://github.com/pradel/create-react-app-esbuild/tree/main...
I can think of at least a few cases like that where Webpack works better, but esbuild is (hopefully) going to catch up. It'd be ideal if Webpack and other bundler tools ditched their homegrown build tools and replaced them with esbuild.
I would quibble with the word "solves". Webpack is a tool building tool. With Webpack, you can build a tool to solve your edge case problem, as long as you're willing to spend a lot of time and dig through random Github issues for your dependencies. Webpack itself however does basically nothing.
This is not the case. I love esbuild and hope to see it go far, but Webpack does out of the box most of what esbuild (today) does as well, with the notable exception of TypeScript /jsx transpilation. For more advanced scenarios, like dealing with css modules, you do need plugins -- but esbuild doesn't support most of these scenarios today at all.
It's like saying VS Code does nothing: you probably want extensions to help you out and let you do more complex things more easily, but it doesn't "do nothing" out of the box.
https://bundlers.tooling.report/
webpack: 43.5/48
rollup: 40.5/48
parcel: 31.5/48
Let's be concrete. How do I do dynamic imports in Webpack?
> Webpack was one of the first bundlers to use Dynamic Imports as a signal for creating code-splitting boundaries.
> Unlike multiple entries, split points created using Dynamic Imports consistently result in a separate bundle being created without customizing optimization.splitChunks.
Okay, but what does that mean? How do I make it work? What are the actual configuration settings? The site gives you no clues.
All right, let's go to https://webpack.js.org/guides/code-splitting/#dynamic-import... and read the docs.
Haha, okay, yes "Webpack" can totally do dynamic imports. All you have to do is read 50 pages of confusing docs first and craft a perfect config file. If you're familiar with Webpack, it shouldn't take more than 1 or 2 hours (my serious, no joking estimate).
Or you could use a bundler tool instead of a bundler tool tool.
The trickiest part was to make Tailwind CSS work. I used to do that via postcss plugin, but just running that plugin even without Webpack takes 15 seconds. Finally, with some modifications in my CSS I made it work, and purged the unused styles just by using PurgeCSS API manually.
The setup got a bit hairier than with Webpack, but it builds damn fast now.
[0] https://twitter.com/adamwathan/status/1366514152517337089
HMR is pretty much the last missing piece to make this the only JS bundling and dev tool you need. It would be a bad decision to omit it.
Or have your editor and browser window tiled next to each other? Given how often FE development dabbles with design, using at least one decently sized monitor seems requisite.
And aren't FEers generally tweaking design in the DOM via a browser's developer tools when they're not sure what they want yet, copying back over into source once the design is finalized? Seems downright unpleasant to modify styling in the way you've described, and odd given there's a fantastic IDE in every major browser for styling exploration.
Took me a good while to understand the issue is with HMR and not my code. I restart the dev server many times a day just to be sure or when things inevitably explode.
Yes, just hook up to the reloading event of HMR on the client-side and call `window.location.reload()` when that happens, now you have traditional "live reload".
Out of interest, if you’re bundling with Esbuild before running, how do you cope with native dependencies?
Our build command (in a bash script file to avoid string escaping issues) is:
find src -type f \( -name '*.js' -o -name '*.ts' -o -name '*.sql' \) -print0 \
| xargs -0 ./node_modules/.bin/esbuild --platform=node --format=cjs --outdir=dist --loader:.sql=textI’ve plugged in Esbuild, I have used bundle mode though to see what it’s like, it works fine if I external all of my node modules, it builds in 0.23 seconds (approx 350 source files in my project).
Nodemon now watches for TS file changes and exec’s the esbuild on every start.
Thank you for the pointer to this as this will be a much needed productivity boost!
I’ll try bundling some node modules when I have some time but it will take more work as I use Yarn PnP (I’ve found a plug-in so will definitely try that)
now we need to rewrite tsc/babel/npm/eslint/etc... in a language that compile down to native binary that is also cross platform (like go or rust),
to gain the same performance improvements across the entire JS tool-chain.
* based on the benchmark on their landing page.
I’m sure it would make sense to rewrite certain things in Rust or Go (then possibly pull them into Node as native modules) but they’re not magic. Good engineering will win out no matter what.
The problem with any interpreted language is that to run the tool you need all the source and all the dependencies plus the interpreter in something like their intended versions to be present in the right locations on disk. This is a huge PITA, and if you're say writing JavaScript targeting ES5 but your tools are targeting ES2020 or vice versa, there can be painful yak shaving sessions getting everything on the same page.
Essentially all developer tools should be static binaries.
1) Modern JITed JS is fast. It's closer to Java than it is to what we typically think of as "interpreted languages".
2) "something like their intended versions to be present in the right locations on disk"; Node packages really just depend on the user having a new-enough install of Node and NPM, somewhere in the path. Any dependencies that live on npm will install to the local directory to ensure against conflicts or permissions issues. The only exception I can think of is that occasionally (looking at you, node-sass) npm dependencies will have to do a native build of something and require a local C/++ compiler somewhere in the path. This is pretty rare in my experience, and isn't a super brittle dependency anyway.
3) "if you're say writing JavaScript targeting ES5 but your tools are targeting ES2020 or vice versa, there can be painful yak shaving sessions getting everything on the same page"; this really doesn't happen in any distributed NPM dependencies I've worked with. The great majority are written for the least-common-denominator of environments; if they use ES2020 internally, they'll do their own transpilation step to make sure you can use them in older environments. Also, "or vice versa" really doesn't apply because all ES versions are 100% backwards-compatible. You just need a Node version new enough to cover the newest features that any of your code or dependencies is using. Dependencies will be as compatible as they can be; your own code is under your control. Virtually never an issue.
2. Node is much better than Python because the correct location on disk is pretty much project/node_modules. However, it is still that case that e.g. Babel was broken by Node 12.17.0 [1] last year, which necessitates something like NVM. I don't want to deal with that for my build tools. I just want a binary that is known to work to continue to work until it is replaced.
3. Yes, conventionally everything in Nodeland was written out to dist as ES5. This also sucks ass because now you end up shipping a bunch of ES5 crap to your end users even though you aren't targeting ES5. It is very hard to build an actual ES2020 module unless you're willing to not use external dependencies at all. Snowpack et al are shifting this slowly, but it has barely even begun as a trend.
[0] https://nodejs.org/en/blog/release/v12.17.0/ https://www.google.com/search?q=babel+compat+data+corejs3+sh...
The caveat here is that it's not nearly as fast for code that isn't properly warmed up, even in the face of herculean efforts to make it so.
Now, you could argue that JS encourages complex, inefficient abstractions and over engineering and Go encourages the opposite. That, I’d believe.
Suggesting more bleeding edge tech is not a good argument to demonstrate that front end development got better.
In my experience, it changed, it improved on many aspects, but it's still a pile of unstable crap running on the power of hype and over-enthusiastic junior engineers.
My point is that there has been a lot of evolution and improvement, but developer sanity is one of the few things that have just gone worse.
It is dishonest to look only at the bright side of modern frontend coding and forgetting the node_modules nightmare, the incredibly obtuse language, the slow compilation times, the myriad of CSS frameworks that are invented because CSS is an absolute pain in the arse for modern design, etc., the fact that every JS tool either is core to the whole circus and is maintained by a stressed out, underpaid person in the middle of nowhere, or has a minimum of 5k Github issues and a major version released every 3 months, and every time you get a problem you're told "haven't you tried the new alpha release of the big rewrite we've just started?".
It is absolute madness, not just frustrating. But yeah, React is cool.
It's amazing what browsers can do these days without any build step!
[0]: https://starboard.gg
MDX is another neat step, it's markdown + react components and fits in very well with next.js: https://github.com/hashicorp/next-mdx-remote
Vue, and Svelte to just get an idea of what other components systems are like. They're all equally capable and just have different tradeoffs and styles. Keep an eye on Svelte in particular as its next.js-like system (SvelteKit) is working on a major revamp to be serverless-first and is quite interesting. Once you learn one component system it's easy to switch between them all--they're all cribbing and building on top of each other's ideas. The whole space is innovating in a great way.
Web components are good to learn and compare to component frameworks above. It's still a changing space but points to a nice future where we can all just publish and share components.
I'd be willing to stake money on React, Vue, next.js and Svelte surviving at least 2 more years - roughly in descending order of probability, though all three well above 50%.
It’s easy to forget that hooks were only introduced in React 16.8, which was released just over two years ago. And yet today, if you visit popular forums for React devs like /r/reactjs, you’ll find no shortage of people who will tell you that class-based components are ancient history and anyone who isn’t using hooks for everything today is a dinosaur.
This year, I’ve noticed a spate of online discussions about state management within the React ecosystem. Just like the hooks vs. classes debate of yesteryear, there is a striking contrast between those forever keen to do the new thing (sometimes using React’s own context and hooks, sometimes using relatively new libraries) and those who prefer to rely on more tried-and-tested tech like Redux and MobX.
In any situation like this, it’s sensible to question how much real progress is being made, and how much of the change is just lost productivity due to churn in tools and “best practices”. If so many developers think it’s normal to swap out most of your tools and coding style every couple of years or less, you have to wonder how long they expect anything they ever build to be maintained for or how often they think longer-lived software should have big rewrites just to update the tools…
In contrast, esbuild is shaping up to be an excellent tool. There seems to be a healthy focus on doing one common and important job well, it’s much better at it than the popular tools it potentially replaces, and it also seems designed to play nicely with others. It reminds me of the early days of 6to5/Babel, actually. This is what we need more of in the front-end web dev community right now.
Next.js is pretty corporate-friendly. Very easy to split things up and have many folks and teams working on monoliths or services with it.
I switched to desktop .Net development in 2001 did that for almost 15 years.
Since then I have been back on the web. I am full-stack so I find myself switching between front-end and back-end frequently.
I am enjoying my time more in the world of TypeScript, VS Code, and Angular than I am writing the back-end REST APIs in .Net Core and Visual Studio.
I was dreading going back to web development when I switched back again but recently it has turned out to be nicely structured, performant, logical and enjoyable.
Edit: professionally, that is; when I do front-end related stuff for myself, it's fine, but they are small and I keep things simple - vanilla JS where needed, etc.
The work Evan does is seriously impressive.
i'm curious why you didn't go the direction of adding this functionality to CDK directly? i'd like to use some of the functionality in here like live lambda development, but i also don't want to take on converting my org's already built CDK extensions and deal with migrations.
We had to change the build process of Lambdas to support deploying a mock version of the function. And we need to add a new command that deployed the debug stack.
Here's how it works internally — https://docs.serverless-stack.com/live-lambda-development
Your existing CDK app should work with SST. The main difference is that SST deploys per stage (or environment). This allows you to do `sst start` that goes to one environment and `sst deploy --stage prod` that goes to another.
One thing I haven't seen yet is support for SCSS and CSS Modules. It looks like projects on those would need to switch to emotion+styled-components or styled-system, which would be a big move.
If anyone uses relay, I started an issue here about using it with next-gen bundlers like esbuild: https://github.com/facebook/relay/issues/3319
For those who don't know, relay is a graphql system by facebook. It seems dependent on babel (to my knowledge?) Two developments on this front:
1. @sciyoshi built an esbuild proof of concept for relay: https://gist.github.com/sciyoshi/34e5865f2523848f0d60b4cdd49...
2. Meanwhile, the compiler has been being quietly rewritten in rust: https://github.com/facebook/relay/tree/master/compiler. They're also claiming that it will include type generation.
https://www.snowpack.dev/guides/optimize-and-bundle#option-1...
https://github.com/bpierre/esbuild-config
(disclaimer: I am the author)
Would be great to get some insights how people are mitigating the lack of bundle splitting in non-esm output right now. Thanks!
- Using the Language Server Plugin in editors
- `npx tsc --noEmit` in a pre-commit hook
- `npx tsc --noEmit` in CI
I also have a `tsc --watch` running in a vscode window that highlights syntax and typing errors as I develop.
Is there anything else I am missing?