Introduction to Babel
Babel is a JavaScript compiler. Babel transpiles/converts modern JavaScript ( ECMAScript 2015+ ) code into a backward compatible version of JavaScript in current and older browsers or environments.
Features of Babel
Here are the main things Babel can do for you:
- Transform syntax
- Polyfill features that are missing in your target environment (through @babel/polyfill)
- Source code transformations
Plugins
Babel is a compiler (source code => output code). Like many other compilers it runs in 3 stages: parsing, transforming, and printing.
Now, out of the box, Babel doesn’t do anything. It basically acts like const babel = code => code;
by parsing the code and then generating the same code back out again. You will need to add plugins for Babel to do anything.
Babel is built on a plugin system that parses your modern JavaScript into an AST ( Abstract Syntax Tree ) and rewrites it into a version that can be interpreted by the browser.
Babel plugins are small JavaScript programs that instruct Babel on how to carry out transformations to the code.
Since Babel plugins are small, so generally one plugin covers one feature.
Presets
Instead of adding all the plugins we want one by one, we can use a “preset” which is just a pre-determined set of plugins.
Babel’s concept of presets, helps us determine which feature you want to use broadly. So Presets are groups of plugins that babel uses for its transpilation.
Common ones are :
@babel/preset-env
@babel/preset-flow
@babel/preset-react ( for React and it supports JSX Syntax )
@babel/preset-typescript
@babel/preset-env
@babel/preset-env
is a smart preset that allows you to use the latest JavaScript without needing to micromanage which syntax transforms (and optionally, browser polyfills) are needed by your target environment(s). This both makes your life easier and JavaScript bundles smaller!
Without any configuration, this preset will include all plugins to support modern JavaScript (ES2015, ES2016, etc.)
Why use @babel/preset-env?
Earlier we used to transpile arrow functions to ES5 using ‘babel-plugin-transform-es2015-arrow-functions’ plugin. The problem is that most of the browsers are getting better day by day, and many of them now support the latest JavaScript features like arrow functions. If they support it then you don’t want to transpile it because if you do then your app gets bigger and slower. So in babel 7 they introduced @babel/preset-env
The most popular preset is @babel/preset-env because it helps us specify what level of compatibility you need for the targets you intend to support and babel will automatically install the appropriate transformation plugin
For example, you can create a .babelrc file in the root of your project. and add support for last 2 versions of the browser.
This will ensure that when the browser is updated it will stop transpiling of the old browser version and will transpile for the new one.
Configuration files:
Presets can take options too. Rather than passing both cli and preset options from the terminal, let’s look at another way of passing options in the configuration files.
There are two types of configuration files . You can use either of those based on your requirement:
1-babel.config.js ( Project-wide configuration: You can use it if you want to programmatically create configuration or if you want to compile node modules )
2-.babelrc ( File-relative configuration: If you have a static configuration that only applies to a single package ) https://babeljs.io/docs/en/config-files#file-relative-configuration
You can often place all of your repo configurations in the root babel.config.js
. With "overrides", you can easily specify the configuration that only applies to certain subfolders of your repository, which can often be easier to follow than creating many .babelrc
files across the repo.
.babelrc
Its a configuration file for babel. You can specify here:
-Which plugins and presets to be used.
-Which files to ignore
-And different settings for different targets
You can also put these settings in your package.json file but it is done a little less frequently. Many projects include babel with a bundler like webpack as part of their compilation pipeline, but you can still use babel by itself.
Babel loads .babelrc
(and .babelrc.js
/ package.json#babel
) files by searching up the directory structure starting from the "filename" being compiled.
Modules: false means Hey babel don’t do anything with the modules let webpack handle it. Webpack now understands modules natively, it does not have to worry about common js. So babel only includes the code for a function that you are using from the node_modules and not the rest of it. This is called tree shaking or live code inclusion
//.babelrc
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"browsers": [ "last 2 versions" ]
},
// Madule: false means Hey babel don't do anything with the module let babel handle it.
"modules": false
}
]
]
"plugins": []
}
- Plugins run before Presets.
- Plugin order is first to last.
- Preset ordering is reversed (last to first).
// Another example for .babelrc file
// .babelrc
{
"plugins": ["transform-decorators-legacy", "transform-class-properties"]
"presets": ["es2015", "react", "stage-2"]
}
Polyfill
A polyfill is code that implements a feature on web browsers that do not support the feature.
When we use modern features of the language, some engines may fail to support such code. Here Babel comes to the rescue
In order for certain features to work they require certain polyfills. You can satisfy all Babel feature requirements by using @babel/polyfill.
There are two parts in Babel:
a-Transpile the code
b-Polyfill.
The transpiler rewrites the code, so syntax features are covered. But for new functions, we need to write a special script that implements them. JavaScript is a highly dynamic language, scripts may not just add new functions, but also modify built-in ones so that they behave according to the modern standard. There’s a term “polyfill” for scripts that “fill in” the gap and add missing implementations.
@babel/polyfill
Since Babel assumes that your code will run in an ES5 environment it uses ES5 functions. So if you’re using an environment that has limited or no support for ES5 such as lower versions of IE then using @babel/polyfill will add support for these methods. Make sure to add it as a dependency and not dev dependency. If you don’t install and configure @babel/polyfill then babel will not be able to convert the async await
functions to a javascript that most browsers can understand and you will get an error.
npm install @babel/polyfill
There are two ways to configure @babel/polyfill:
- Add
“useBuiltIns”: “usage”
to your babel configuration file( .babelrc ).
{
"presets": [
[ "@babel/preset-env", {
"modules": false,
"targets": {
"browsers": [
"last 2 Chrome versions",
"last 2 Firefox versions",
"last 2 Safari versions",
"last 2 iOS versions",
"last 1 Android version",
"last 1 ChromeAndroid version",
"ie 11"
]
},
"useBuiltIns": "usage"
} ]
]
}
2. Or, add this to your webpack.config.js
file
entry: ["@babel/polyfill", "./src/index.js"],