Babel Loaders
Set up Babel with Webpack to transpile modern JavaScript (ES6+) into browser-compatible code using babel-loader and presets.
Babel Loaders
Modern JavaScript uses features like arrow functions, template literals, destructuring, and classes — but older browsers do not support them. Babel is a JavaScript compiler that transpiles modern syntax into backwards-compatible code. In this episode you will integrate Babel into Webpack using babel-loader.
What Is Babel?
Babel reads modern JavaScript and outputs equivalent code that works in older environments:
// Input (ES6+)
const greet = (name) => `Hello, ${name}!`;
// Babel output (ES5)
var greet = function(name) {
return "Hello, " + name + "!";
};
What Are Loaders?
Webpack can only understand JavaScript and JSON natively. Loaders teach Webpack how to process other file types — transforming them before they are added to the bundle.
| Loader | What It Processes |
|---|---|
babel-loader | Modern JavaScript → compatible JavaScript |
css-loader | CSS files → JavaScript module |
sass-loader | SASS/SCSS → CSS |
file-loader | Images/fonts → output files with URLs |
ts-loader | TypeScript → JavaScript |
Each loader is specified in the module.rules array of webpack.config.js.
Step 1: Install Babel Packages
npm install babel-loader @babel/core @babel/preset-env --save-dev
| Package | Purpose |
|---|---|
babel-loader | The Webpack loader that passes files through Babel |
@babel/core | The core Babel compiler engine |
@babel/preset-env | A smart preset that determines which transformations are needed based on your target browsers |
Step 2: Add the Loader Rule
Add the Babel loader to the module.rules array in webpack.config.js:
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
],
},
Understanding the Rule
| Property | Value | Purpose |
|---|---|---|
test | /\.js$/ | A regex that matches files ending in .js |
exclude | /node_modules/ | Skip library code — they should already be transpiled |
use.loader | 'babel-loader' | The loader to apply to matched files |
use.options.presets | ['@babel/preset-env'] | Tells Babel which transformations to apply |
The test property uses a regular expression. /\.js$/ matches any filename ending with .js. The backslash escapes the dot (which is a regex wildcard), and $ means "end of string."
What @babel/preset-env Does
@babel/preset-env is a "smart" preset that automatically determines which JavaScript features need to be transpiled based on your target environment. Instead of manually listing individual Babel plugins, you specify which browsers to support:
// In package.json — add a browserslist field
{
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}
| Query | Meaning |
|---|---|
> 1% | Browsers with more than 1% global market share |
last 2 versions | The last 2 versions of each browser |
not dead | Exclude browsers without official support |
If all your target browsers support arrow functions natively, Babel will not transform them — keeping the output smaller and faster.
Step 3: Build and Test
npm run build
Webpack now passes every .js file through Babel before bundling. If you build in development mode and inspect the output, you will see that modern syntax has been converted to compatible code.
Using a Separate Babel Config File
For larger projects, move Babel options to a separate config file:
.babelrc
{
"presets": ["@babel/preset-env"]
}
Then simplify the Webpack rule:
{
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader',
}
Babel automatically looks for .babelrc or babel.config.json in the project root. This keeps the Webpack config clean and makes Babel settings reusable across tools.
Adding Babel Plugins
// .babelrc with additional plugins
{
"presets": ["@babel/preset-env"],
"plugins": [
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-optional-chaining"
]
}
Plugins handle individual transformations that are not included in presets. @babel/preset-env covers most standard features, but experimental or proposal-stage features require explicit plugins.
How Loaders Process Files
Source File (.js)
↓
test: /\.js$/ → Does the filename match? Yes
↓
exclude: /node_modules/ → Is it in node_modules? No
↓
babel-loader → Passes file through Babel
↓
@babel/preset-env → Transpiles modern syntax
↓
Webpack → Adds the transformed code to the bundle
Multiple Loaders
A single rule can chain multiple loaders. They execute in reverse order — from the last loader to the first (right to left in the use array). You will see this in action with CSS and SASS loaders in the next episodes.
use: ['loader-c', 'loader-b', 'loader-a']
// Execution order: loader-a → loader-b → loader-c
Updated webpack.config.js
const path = require('path');
module.exports = {
mode: 'development',
devtool: 'eval-source-map',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
devServer: {
static: { directory: path.resolve(__dirname, 'dist') },
port: 3000,
open: true,
hot: true,
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
],
},
};
Key Takeaways
- Loaders teach Webpack how to process non-standard file types — they transform files before bundling
- Babel transpiles modern JavaScript (ES6+) into code that older browsers can run
babel-loaderconnects Babel to Webpack;@babel/coreis the engine;@babel/preset-envdecides what to transpile- The
testproperty uses regex to match files;excludeskipsnode_modules @babel/preset-envuses yourbrowserslistconfig to only transpile what is needed- Babel config can be inline in Webpack or in a separate
.babelrcfile - Multiple loaders in a rule execute in reverse order (right to left)