JavaScript Bundlers & Transformers
I’ve been using Next.js for a long time, from having to configure everything to now almost zero setup, so I took some time to explore the evolution of JavaScript ecosystem tools.
Nowadays, we almost don't need to write a bunch of configuration files.
I also looked at some of the differences between transformers, bundlers, and so on.
Currently, Next.js uses: turbopack for bundling, and swc for transformation.
Vite seems to be used more in Vue projects.
I also reviewed some tool comparisons and benchmarks.
This article doesn’t flow well at all.
…
TL;DR
- Some tools can act as both transformers and bundlers - at first it's separated, but after digging deeper, they tend to be ambiguous.
- SWC is often compared to Babel and is generally classified as a transformer.
- Turbopack is often compared to webpack, as well as esbuild, vite, parcel, rollup, etc. - these are generally classified as bundlers.
- Starting from Next.js 12, the transformer used is SWC (written in Rust).
- For Next.js 14, the next dev command uses Turbopack (written in Rust).
https://nextjs.org/blog/next-14#nextjs-compiler-turbocharged
SWC (Rust)
- Created to replace Babel.
- The author later joined Vercel, and Next.js started using it as the default compiler from version 12 (but it can conflict with Jest and fail to upgrade).
- Deno (another Node.js) also uses SWC to speed up TypeScript startup.
- Turbopack and Parcel both use SWC (both written in Rust).
- Webpack uses Babel, but can also use the
swc-loader
.
Features
- Compilation
- Bundling (
swcpack
)
- Minification
- Transforming with WebAssembly
- Usage inside webpack (
swc-loader
)
- Improving Jest performance (
@swc/jest
)
- Custom Plugins
Typescript
Many tools have built-in TypeScript transpilation capabilities. 3-5 are bundling tools, and they may use Babel or SWC as the transpilation tool, usually as an expanded plugin.
The TypeScript to JavaScript conversion is done first, then Babel or SWC transforms it into browser-understandable JavaScript.
Before, I didn't understand that TypeScript is not an independent tool for TS->JS conversion, but rather for better IDE DX. The actual TS->JS conversion is handled by the various bundling tools.
- Babel with @babel/preset-typescript
.babelrc
{ "presets": [ "@babel/preset-env", "@babel/preset-typescript" ] }
- esbuild
JavaScript, CSS, TypeScript, and JSX built-in
zero config ☺️
- Webpack with
ts-loader
andbabel-loader
babel-loader only (simple, fast, no type check, only transform)
{ test: /\.tsx?$/, use: 'babel-loader', options: { presets: ['@babel/preset-typescript'] } }
use both (slow but reliable, for production)
{ test: /\.tsx?$/, use: [ 'babel-loader', 'ts-loader' ] }
use both with transpileOnly (balancing..)
"Transpile" means the process involves less work than "Transform", as it skips type checking and directly converts TS to JS.
{ test: /\.tsx?$/, use: [ 'babel-loader', { loader: 'ts-loader', options: { transpileOnly: true } } ] }
- Rollup with
@rollup/plugin-typescript
rollup.config.js
// rollup.config.js import typescript from '@rollup/plugin-typescript'; export default { input: 'src/index.ts', output: { // ... }, plugins: [ typescript({ tsconfig: './tsconfig.json' }) ] };
- Parcel (default uses SWC)
TypeScript is a typed superset of JavaScript that compiles to JavaScript. Parcel supports TypeScript out of the box without any additional configuration.
zero config, too ☺️
Vite
some pov from official doc.
The Problem: Slow Server Start
Over time we have seen tools like webpack, Rollup and Parcel, which greatly improved the development experience for frontend developers.
When cold-starting the dev server, a bundler-based build setup has to eagerly crawl and build your entire application before it can be served.

Vite improves the dev server start time by first dividing the modules in an application into two categories: dependencies and source code.
Vite pre-bundles dependencies using esbuild. esbuild is written in Go and pre-bundles dependencies 10-100x faster than JavaScript-based bundlers.

use esbuild in dev mode
Why Not Bundle with esbuild?
Rollup is more mature and flexible in these regards. That said, we won't rule out the possibility of using esbuild
for production build when it stabilizes these features in the future.
use Rollup in production mode
Turbopack (Rust)
Turbopack is a bundler that uses SWC for the transformation and compilation process, similar to how Webpack uses Babel.
- Turbopack was written by the Webpack author and the Next.js team, in Rust.
- Turbopack currently supports Next.js, and there are plans to integrate it with Svelte in the future.
https://turbo.build/pack/docs/why-turbopack
Why Turbopack?
We migrated away from several JS-based tools. Babel, gone. Terser, gone. Our next target was another JS-based tool, webpack.
A new generation of native-speed bundlers were emerging, but after assessing the bundlers on the market, we decided to build our own. Why?
esbuild doesn’t have a concept of ‘lazy’ bundling - it’s all-or-nothing, unless you specifically target only certain entry points.
Bundling vs Native ESM
Frameworks like Vite use a technique where they don’t bundle application source code in development mode. Instead, they rely on the browser’s native ES Modules system. This approach results in incredibly responsive updates since they only have to transform a single file.
we wanted Turbopack to bundle the code in the development server. Turbopack can do it much faster, especially for larger applications, because it is written in Rust and skips optimization work that is only necessary for production.
These days, browsers can natively handle ES modules, which lets Vite just update individual files (using esbuild) and notify the browser (over WebSocket) for hot reloading. But as the project grows bigger, all those individual requests can start to become a bottleneck with the native ESM approach.
A traditional bundled setup is still better in a lot of cases - having one bigger file request is usually better than tons of smaller ones, even during development.
That's why Turbopack wants to do the bundling step right in the dev server, just like Webpack.
But Turbopack can do it much faster, and it avoids the startup slowness you can get from Vite's super granular modularization (especially with vue SFC).
Incremental Computation
There are two ways to make a process faster: do less work or do work in parallel.
Lazy bundling
Early versions of Next.js tried to bundle the entire web app in development mode. We quickly realized that this ‘eager’ approach was
less than optimal. Modern versions of Next.js bundle only the pages requested by the dev server.
esbuild doesn’t have a concept of ‘lazy’ bundling - it’s all-or-nothing, unless you specifically target only certain entry points.
esbuild is crazy fast and great as a bundler, but the downside is it doesn't have any caching capabilities. That's where Turbopack is trying to step in and fill that gap.
Side Note:
https://github.com/vercel/turbo
Turbo includes two project
- Turbopack: an incremental bundler (the successor to Webpack)
- Turborepo: an incremental build system
- The Turbo engine: a low-level incremental computation and memoization engin
In the future, Turborepo and Turbopack will merge into a single toolchain--Turbo--that can be used as either a bundler or a build system or both.
https://turbo.build/pack/docs/roadmap
esbuild, Vite, Snowpack, WMR Differences
These are some of the key differences between the new generation of build tools:
- esbuild is excellent at bundle size, but lacks support for modern frontend features like HMR and SSR.
- WMR is no longer maintained as of March 2024.
- Snowpack is no longer maintained as of April 2022.
- Vite is the current winner in this space.
esbuild, SWC, TSC, Babel Benchmark
https://datastation.multiprocess.io/blog/2021-11-13-benchmarking-esbuild-swc-typescript-babel.html
Bundlers typically use a transformer under the hood and handle turning multiple JavaScript source files into one JavaScript file (a bundle). Some newer transformers like esbuild and swc work as bundlers too.
- The Babel author later went on to create Rome, another transformer, and then worked on Biome.
Biome is the official fork of Rome and it will continue to be Rome’s legacy.
- The benchmark shows that esbuild and SWC significantly outperform Babel and TypeScript in terms of performance.
Minification Benchmark
The benchmark results indicate:
- @swc/core and uglify-js take turns being the top performers in different test cases.
- @swc/core and terser also take turns being the top performers in different test cases.
- Terser sometimes times out.
terser
- used by Webpack and Rollup for bundling.
babel-minify
- a Babel plugin
uglify-js
- Uglify-js is on par with SWC in some cases.
esbuild
- used by Vite, Snowpack, and Parcel for bundling.
swc
- a strong performer overall.
- There is a separate article that provides the results of comparing different tools for code minification.
Babel
There's a very detailed article explaining Babel, which is the most comprehensive I've seen.
https://awdr74100.github.io/2020-03-16-webpack-babelloader/
References
https://eisenbergeffect.medium.com/an-esbuild-setup-for-typescript-3b24852479fe
https://parceljs.org/languages/typescript/
https://webpack.js.org/configuration/other-options/#parallelism
https://turbo.build/pack/docs/core-concepts#function-level-caching
https://v2.vitejs.dev/guide/why.html
https://dev.to/132/i-never-need-webpack-or-babel-anymore-3o45
https://github.com/preactjs/wmr