JavaScript is the only language that runs in the browser, but even then not all browser vendors implement the latest feature of JavaScript, or they did implement it, but then again it’s only for the latest version of the browser. So what if we, as developers, want to implement a feature of JavaScript that’s sadly not yet available in the browser? What if we also want to support older browser versions and not only the latest one? This is the problem that has been solved by Babel, the web developer tool for transpiling JavaScript code into older version of it.
In a very generic non-jargon way, it means Babel takes a modern JavaScript code and turn it into an older version that’s understood by browsers.
For example, let’s take arrow function, which is released in ES6
[1, 2, 3].map((n) => n + 1);
This code will work fine in recent versions of Chrome (61+ if I’m not mistaken) but not in Internet Explorer. So to make the code work in IE, we have to transpile the code into ES5 version.
[1, 2, 3].map(function(n) {
return n + 1;
});
This is what Babel does in a nutshell. It takes modern JavaScript and rewrite it into a prior version that’s compatible with older browsers. It also allows us to use experimental or very recent release of JavaScript version into our code.
Babel Setup
To install Babel, go into your project root directory and hit the command line:
npm install --save-dev @babel/core @babel/cli
npm install --save @babel/polyfill
npm install --save-dev @babel/preset-env
Then create a new config file named babel.config.js
with this content:
const presets = [
[
"@babel/env",
{
targets: {
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1",
},
useBuiltIns: "usage",
},
],
];
module.exports = { presets };
Note that the browsers list above is just an arbitrary example. You will have to adapt it for the browsers you want to support. Now let’s run Babel to transpile all the code from src/
directory into lib/
:
npx babel src --out-dir lib
To run babel on a single file you can use:
npx babel script.js
Explaining the installed packages
All npm packages of Babel are scoped under @babel
to allow a structured and specific babel packages order. The packages we have installed above are the minimum we needed to run Babel. @babel/core
is the main functionality of Babel that’s responsible for transpiling your code. It needed some kind of interface for access. @babel/cli
allows you to access Babel from the Terminal, hence we can run the npx babel
command. We can add arguments like the --out-dir
option above. You can view the rest of the options accepted by the cli tool by running it with --help
. But the most important options for us to learn right now are --plugins
and --presets
Plugins
These are small JavaScript programs responsible for carrying out the transpiling tasks. For example, to transform arrow functions into a regular function, we can use @babel/plugin-transform-arrow-functions
official plugin.
npm install --save-dev @babel/plugin-transform-arrow-functions
Then add it to our babel.config.js
const presets = [
[
"@babel/env",
{
targets: {
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1",
},
useBuiltIns: "usage", // for using babel-polyfill
},
],
];
const plugins = ["@babel/transform-arrow-functions"]
module.exports = { presets, plugins };
Now we are transforming arrow functions into regular functions.
Presets
But then again, specifying each and every one of the plugins would be exhausting, isn’t it? That’s why Babel has presets, which is a pre-determined set of plugins.
Just like with plugins, you can create your own presets to share any combination of plugins you need. For our use case here, there’s an excellent presets named env
which support all modern JavaScript (ES2015, ES2016, etc.). You can use it from the terminal.
npm install --save-dev @babel/preset-env
npx babel src --out-dir lib --presets=@babel/env
Or use the config file like how we have done above.
Preset targets option
The target options of presets will allow you to target specific version of browsers to support, but it can also be smarter than that.
For example, let’s say we want to support the last 3 versions of every browser, but for Safari let’s support all versions since Safari 8
const presets = [
[
"@babel/env",
{
targets: {
"browsers": ["last 3 versions", "safari >= 8"]
},
useBuiltIns: "usage",
},
],
];
const plugins = ["plugin-transform-arrow-functions"]
module.exports = { presets, plugins };
Running Babel with webpack
In order to run babel with webpack, we can use the babel-loader
from webpack and put our babel configuration into it. So on our webpack.config.js
:
entry: [
'babel-polyfill',
// your app scripts should be here
],
module: {
loaders: [
// Babel loader compiles ES2015 into ES5 for
// complete cross-browser support
{
loader: 'babel-loader',
test: /\.js$/,
// only include files present in the `src` subdirectory
include: [path.resolve(__dirname, "src")],
// exclude node_modules, equivalent to the above line
exclude: /node_modules/,
query: {
// Use the default ES2015 preset
// to include all ES2015 features
presets: ['@babel/env'],
plugin: ['@babel/plugin-transform-arrow-functions']
}
}
]
}
By keeping the presets and plugins information inside the webpack.config.js
file, we can discard babel config file from our project directory.