Building on top of our last post — Minimal Webpack Setup , we will be introducing Babel to work with Webpack in order to transpile our Javascript codes — that are written in latest Javascript syntax— to codes written in older syntax that are supported by our target browsers.
We will take care of Babel first, and finish it off by intergrating it with Webpack.
F*ck it! Do it!! 🎆
Install some npm packages
npm i -D @babel/core @babel/preset-env babel-loader
(If you are using React, npm i -D @babel/preset-react
too.)
And last one:
npm i @babel/polyfill
Note that ‘ @babel/polyfill’ will have installed the core-js
(source of our polyfills) and regenerator-runtime
packages too. The inclusion of all of that stuff will be handled for you ❤️ by Babel accordingly as we will see how to set that up next.
Create the .babelrc file
Edit (3/6/2019)
The following is the babel loader I’m currently using:
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "entry"
}
],
"@babel/preset-react" // removes this entry if not using React
]
}
As you will see, @babel/preset-env and @babel/polyfill are the two main components that make it really happen!
About @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!
Basically, all you need to care about is the list of browsers you are going to support, then the @babel/preset-env
will — with the help of the userBuiltIns
key —automatically select all the required transform plugins and polyfills so that your final codes will run properly in your target browsers.
Let’s talk a bit about the effects of polyfills on codesize and ways to reining them in, then we will ram through the rest of this article!
Controlling codesize
Babel can bloat your codesize if you are not careful, especially when using @babel/polyfill
, in which case, it’s recommended to utilize the useBuiltIns
property with the @babel/preset-env
as shown above, because that way, Babel will automatically include only those polyfills(including the regenerator-runtime
file if necessary) that are really needed by your target browsers.
Here is a good summary of using @babel/preset-env
along with different useBuiltIns
values:
Unless nothing else ever works of you, avoid the following usage of @babel/polyfill
:
- Put it in the
entry
of your webpack config:entry: ['@babel/polyfill', './index.js']
. - Use
@babel/runtime
along with the@babel/plugin-transform-runtime
, unless you are building a library, although they both do more or less than@babel/polyfill
and might even solve some of your annoying Babel issues too. Here is a good summary about this. - Most solutions/packages you see posted prior to Babel 7. Always refer to the official doc.
One downside to the useBuiltIns: "entry"
setting is that it will add many potentially useless polyfills to satisfy all of your target browser, whether your code need them or not!
A better method would have delivered only the polyfills that are needed by your code and your user’s browser.
To that end, here are 3 methods I know of that we can try:
- Use
useBuiltIns: "usage"
. This is still experimental in Babel, but see the demo here. - Use polyfill.io — “ It’s a service which accepts a request for a set of browser features and returns only the polyfills that are needed by the requesting browser.”
- Before mounting your app in client, check your API against
window
. If it exists, then it’s already a native API. If not, http fetch the corresponding polyfills. Only then mount your app. This method is more hands-on.
Alright, that’s all I have for you about this kinda stuff.
Now let’s finish this!
Next we will specify our target browsers in a file called .browserslistrc
as recommended by Babel doc, so that Babel will know which polyfill and syntax to spit out.
Create the .browserslistrc file
We use browserlist to specify our target browsers:
# Browsers that we support>0.2%
not dead
not ie <= 11
not op_mini all
Here you can see all of the browsers you are supporting based on the list above.
Note, careful of using last 2 versions
as argued here.
Import @babel/polyfill
Now we will simply do import '@babel/polyfill'
at the very top(before everything else) of our entry file which is the index.js
:
(Note: Skip this if you do useBuiltIns: "usage"
)
// index.jsimport "@babel/polyfill"; import helloWorld from "./helloWorld";...
Integrate with Webpack
This is easy. All you need to do is add this block in the module.rules
array in your webpack.dev.js
(And you will do the same thing with the webpack.prod.js
too.) :
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
}
]
}
Essentially you are saying:
“Hey webpack compiler, skip the
node_modules
altogether, then when you come across a path that resolves to a ‘.js’ file inside of arequire()
/import
statement use thebabel-loader
to transform it before you add it to the bundle.”
OK that’s it! Bye! 🎿