Speed up your Webpack build with esbuild! 🔥
esbuild is a JavaScript bundler written in Go that supports blazing fast ESNext & TypeScript transpilation and JS minification.
esbuild-loader lets you harness the speed of esbuild in your Webpack build by offering faster alternatives for transpilation (eg. babel-loader/ts-loader) and minification (eg. Terser)!
[!TIP] Are you using TypeScript with Node.js?
Supercharge your Node.js with TypeScript support using tsx!
tsx is a simple, lightweight, and blazing fast alternative to ts-node.
<a href="https://github.com/sponsors/privatenumber/sponsorships?tier_id=398771"><img width="412" src="https://raw.githubusercontent.com/privatenumber/sponsors/master/banners/assets/donate.webp"></a>
<a href="https://github.com/sponsors/privatenumber/sponsorships?tier_id=397608"><img width="412" src="https://raw.githubusercontent.com/privatenumber/sponsors/master/banners/assets/sponsor.webp"></a>
Already a sponsor? Join the discussion in the Development repo!
npm i -D esbuild-loader
To leverage esbuild-loader in your Webpack configuration, add a new rule for esbuild-loader matching the files you want to transform, such as .js, .jsx, .ts, or .tsx. Make sure to remove any other loaders you were using before (e.g. babel-loader/ts-loader).
Here's an example of how to set it up in your webpack.config.js:
module.exports = {
module: {
rules: [
- // Transpile JavaScript
- {
- test: /\.js$/,
- use: 'babel-loader'
- },
-
- // Compile TypeScript
- {
- test: /\.tsx?$/,
- use: 'ts-loader'
- },
+ // Use esbuild to compile JavaScript & TypeScript
+ {
+ // Match `.js`, `.jsx`, `.ts` or `.tsx` files
+ test: /\.[jt]sx?$/,
+ loader: 'esbuild-loader',
+ options: {
+ // JavaScript version to compile to
+ target: 'es2015'
+ }
+ },
// Other rules...
],
},
}
In this setup, esbuild will automatically determine how to handle each file based on its extension:
- .js files will be treated as JS (no JSX allowed)
- .jsx as JSX
- .ts as TS (no TSX allowed)
- .tsx as TSX
If you want to force a specific loader on different file extensions (e.g. to allow JSX in .js files), you can use the loader option:
{
test: /\.js$/,
loader: 'esbuild-loader',
options: {
+ // Treat `.js` files as `.jsx` files
+ loader: 'jsx',
// JavaScript version to transpile to
target: 'es2015'
}
}
esbuild-loader can be used in-place of babel-loader to transpile new JavaScript syntax into code compatible with older JavaScript engines.
While this ensures your code can run smoothly across various environments, note that it can bloat your output code (like Babel).
The default target is esnext, which means it doesn't perform any transpilations.
To specify a target JavaScript engine that only supports ES2015, use the following configuration in your webpack.config.js:
{
test: /\.jsx?$/,
loader: 'esbuild-loader',
options: {
+ target: 'es2015',
},
}
For a detailed list of supported transpilations and versions, refer to the esbuild documentation.
esbuild-loader can be used in-place of ts-loader to compile TypeScript.
({
// `.ts` or `.tsx` files
test: /\.tsx?$/,
loader: 'esbuild-loader'
})
[!IMPORTANT] It's possible to use
loader: 'tsx'for both.tsand.tsxfiles, but this could lead to unexpected behavior as TypeScript and TSX do not have compatible syntaxes.
tsconfig.jsonIf you have a tsconfig.json file in your project, esbuild-loader will automatically load it.
If it's under a custom name, you can pass in the path via tsconfig option:
{
test: /\.tsx?$/,
loader: 'esbuild-loader',
options: {
+ tsconfig: './tsconfig.custom.json',
},
},
Behind the scenes:
get-tsconfigis used to load the tsconfig, and to also resolve theextendsproperty if it exists.
The tsconfigRaw option can be used to pass in a raw tsconfig object, but it will not resolve the extends property.
esbuild only supports a subset of tsconfig options (see TransformOptions interface).
Enable isolatedModules to avoid mis-compilation with features like re-exporting types.
Enable esModuleInterop to make TypeScript's type system compatible with ESM imports.
Features that require type interpretation, such as emitDecoratorMetadata and declaration, are not supported.
→ Read more about TypeScript Caveats
tsconfig.json PathsUse tsconfig-paths-webpack-plugin to add support for tsconfig.json#paths.
Since esbuild-loader only transforms code, it cannot aid Webpack with resolving paths.
esbuild does not type check your code. And according to the esbuild FAQ, it will not be supported.
Consider these type-checking alternatives:
- Using an IDEs like VSCode or WebStorm that has live type-checking built in
- Running tsc --noEmit to type check
- Integrating type-checking to your Webpack build as a separate process using fork-ts-checker-webpack-plugin
Use the define option to replace global identifiers with constant expressions:
{
test: /\.[jt]sx?$/,
loader: 'esbuild-loader',
options: {
+ define: {
+ 'process.env.NODE_ENV': JSON.stringify('production'),
+ },
},
}
[!TIP] The loader's
defineworks with all devtools, including eval-based ones. If you're using the plugin'sdefineand it's not working, try the loader instead.
Esbuild supports JavaScript minification, offering a faster alternative to traditional JS minifiers like Terser or UglifyJs. Minification is crucial for reducing file size and improving load times in web development. For a comparative analysis of its performance, refer to these minification benchmarks.
In webpack.config.js:
+ const { EsbuildPlugin } = require('esbuild-loader')
module.exports = {
...,
+ optimization: {
+ minimizer: [
+ new EsbuildPlugin({
+ target: 'es2015' // Syntax to transpile to (see options below for possible values)
+ })
+ ]
+ },
}
[!TIP] Utilizing the
targetoption allows for the use of newer JavaScript syntax, enhancing minification effectiveness.
Webpack's DefinePlugin can replaced with EsbuildPlugin to define global constants. This could speed up the build by removing the parsing costs associated with the DefinePlugin.
In webpack.config.js:
- const { DefinePlugin } = require('webpack')
+ const { EsbuildPlugin } = require('esbuild-loader')
module.exports = {
// ...,
plugins:[
- new DefinePlugin({
- 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
- })
+ new EsbuildPlugin({
+ define: {
+ 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
+ },
+ }),
]
}
[!WARNING] The plugin's
defineoption does not work with eval-based devtools (e.g.,eval,eval-source-map). This is because eval devtools wrap module code ineval()strings, and esbuild's define cannot replace identifiers inside string literals. If you need to usedefinewith eval devtools, use the loader'sdefineoption instead, which transforms files before bundling.
If your project does not use TypeScript, JSX, or any other syntax that requires additional configuration beyond what Webpack provides, you can use EsbuildPlugin for transpilation instead of the loader.
It will be faster because there's fewer files to process, and will produce a smaller output because polyfills will only be added once for the entire build as opposed to per file.
To utilize esbuild for transpilation, simply set the target option on the plugin to specify which syntax support you want.
Depending on your setup, there are two ways to minify CSS. You should already have CSS loading setup using css-loader.
If the CSS is extracted and emitted as .css file, you can replace CSS minification plugins like css-minimizer-webpack-plugin with the EsbuildPlugin.
Assuming the CSS is extracted using something like MiniCssExtractPlugin, in webpack.config.js:
const { EsbuildPlugin } = require('esbuild-loader')
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
// ...,
optimization: {
minimizer: [
new EsbuildPlugin({
target: 'es2015',
+ css: true // Apply minification to CSS assets
})
]
},
module: {
rules: [
{
test: /\.css$/i,
use: [
MiniCssExtractPlugin.loader,
'css-loader'
]
}
],
},
plugins: [
new MiniCssExtractPlugin()
]
}
If your CSS is not emitted as a .css file, but rather injected with JavaScript using something like style-loader, you can use the loader for minification.
In webpack.config.js:
module.exports = {
// ...,
module: {
rules: [
{
test: /\.css$/i,
use: [
'style-loader',
'css-loader',
+ {
+ loader: 'esbuild-loader',
+ options: {
+ minify: true,
+ },
+ },
],
},
],
},
}
esbuild-loader comes with a version of esbuild it has been tested to work with. However, esbuild has a frequent release cadence, and while we try to keep up with the important releases, it can get outdated.
To work around this, you can use the implementation option in the loader or the plugin to pass in your own version of esbuild (eg. a newer one).
[!WARNING]
⚠esbuild is not stable yet and can have dramatic differences across releases. Using a different version of esbuild is not guaranteed to work.
+ const esbuild = require('esbuild')
module.exports = {
// ...,
module: {
rules: [
{
test: ...,
loader: 'esbuild-loader',
options: {
// ...,
+ implementation: esbuild,
},
},
],
},
}
If you'd like to see working Webpack builds that use esbuild-loader for basic JS, React, TypeScript, Next.js, etc. check out the examples repo:
The loader supports all Transform options from esbuild.
Note:
- Source-maps are automatically configured for you via devtool. `sourc
$ claude mcp add esbuild-loader \
-- python -m otcore.mcp_server <graph>