Babel is often introduced during project development to address code compatibility issues. There are three preset modes, respectively, babel-polyfill, babel-Runtime and babel-preset-env. What are the differences between these three modes and which is the better effect of webpack?
The preparatory work
To start the comparison, we need to initialize a WebPack project
npm init babel-test
Copy the code
We are not going to install the webPack 4.x version here, just install the 3.X version
NPM I - D [email protected]Copy the code
Create a new webpack.config.js file in the project root directory and configure it as follows
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin'); Module.exports = {// JavaScript executables entry: {app: ['./main.js'}, output: {// merge all dependent modules into a bundle.js file filename:'bundle.js'Path: path.resolve(__dirname,'./dist'),
},
devServer: {
contentBase: path.join(__dirname, "dist"),
inline: true}, module: {rules: [{// Use the re to match the CSS file to be converted with this loadertest: /\.css$/,
// use: ['style-loader'.'css-loader? minimize'], use: ExtractTextPlugin extract ({/ / conversion. CSS files you need to use the Loader use: ['css-loader']})}, {test: /\.js$/,
use: ['babel-loader']}, plugins: [new ExtractTextPlugin({//.css filename: '[name].css',})]};Copy the code
Package. json is configured as follows
{
"name": "babel-test"."version": "1.0.0"."description": ""."main": "index.js"."scripts": {
"test": "echo \"Error: no test specified\" && exit 1"."start": "webpack --config webpack.config.js"."dev": "webpack-dev-server --open"
},
"keywords": []."author": ""."license": "ISC"."devDependencies": {
"babel-core": "^ 6.26.3"."babel-loader": "^" 7.1.4."babel-plugin-transform-runtime": "^ 6.23.0"."babel-preset-env": "^ 1.6.1." "."css-loader": "^ 0.28.11"."extract-text-webpack-plugin": "^ 3.0.2." "."style-loader": "^ 0.20.3"."webpack": "^ 3.7.0"."webpack-cli": "^ 1.5.3." "."webpack-dev-server": "^ 2.11.1." "
},
"dependencies": {
"babel-polyfill": "^ 6.26.0"."babel-runtime": "^ 6.26.0"}}Copy the code
The packages involved can be installed by performing NPM install, which will not be described here. Here part of the package will be repeated in the next, explain why it is packed like this
The project structure after initialization is as follows
Let’s write some code to main.js
const elements = [1, 2, 3].map((item) => {
return (
console.log('9999'))}); console.log(elements); asyncfunction azumia() {
console.log('begin');
await new Promise((resolve) => {
setTimeout(() => {
resolve();
}, 1000)
})
console.log('done');
}
azumia();
console.log(Object.values({ 1: 2 }));
console.log(Array.isArray([]));
Copy the code
babel-polyfill
Babel-polyfill is designed to emulate a complete ES2015+ environment and is intended for use with applications rather than libraries/tools. And when using babel-Node, the polyfill is automatically loaded. Note here that Babel-Polyfill is introduced into your project once and compiled into production with the project code. And it pollutes global variables. Things like Map, array.prototype. find exist in the global space.
So here you install it into production
npm install babel-polyfill --save
Copy the code
Webpack.config.js can be configured in this way
entry: {
app: ['babel-polyfill'.'./main.js']}Copy the code
Let’s execute the order and start packing
npm run start
Copy the code
The bundled bundle.js file size is 259K, while the bundle size before babel-Polyfill was 4K, which is a lot bigger. So can we reference babel-Polyfill on demand to reduce the package size? The answer is yes, thanks to babel-Runtime.
babel-runtime
Babel-runtime does not pollute global space and built-in object prototypes. Babel-runtime is actually a module that you can use as a dependency for ES2015 support.
If your environment doesn’t support promises, you can include them in your project
Require (" Babel - the runtime/core - js/promise ')Copy the code
To get the Promise.
In this way we compensate for the shortcomings of Babel-Polyfill and achieve the effect of loading on demand. However, in the actual project development process, we tend to write a lot of new ES6 API, and it is troublesome to manually introduce the corresponding package each time, and it is not convenient to maintain, and the repeated introduction of each file also leads to the bloated code.
To solve this problem, we use the babel-plugin-transform-Runtime, which analyzes our AST to see if there are any references to spacers from babel-Rumtime (via mapping), and if so, inserts the required spacers at the top of the current module.
Next we will try to install babel-Runtime and babel-plugin-transform-Runtime
npm install --save babel-runtime
npm install --save-dev babel-plugin-transform-runtime
Copy the code
Since babel-Runtime simply centralizes the library of polyfills, the required polyfills are imported into the project and packaged with the project code, so they are added to the production environment dependencies
Let’s add the following configuration to. Babelrc
{
"plugins": ["transform-runtime"]}Copy the code
The bundle.js package is 63K, which is much smaller than importing polyfill in its entirety. But there are two sides to every story. The downside of babel-Runtime is that it doesn’t emulate instance methods, which are methods on built-in object prototypes, so you can’t use things like array.prototype. find with babel-Runtime. This can only be transcoded with Babel-polyfill, because babel-polyfill adds methods directly to the prototype chain. That’s sad. Is babel-Polyfill going to be introduced in its entirety? Another way to fix this is to use babel-preset-env
babel-preset-env
Babel-preset -env automatically determines plugins and polyfills you need based on the current running environment. According to the support status of each ES standard feature in different browsers and Node versions, the mapping relationship between a feature and plugins is maintained, and the required plugins are finally determined. For detailed configuration instructions, click here
Let’s modify the configuration of babelrc
{
"presets": [["env", {
"targets": {
"chrome": 52,
"browsers": ["last 2 versions"."safari 7"]},"modules": false."useBuiltIns": "usage"."debug": false}}]]Copy the code
UseBuiltIns is whether to enable automatic support for polyfill, which automatically adds the poly-fill required for each file. Let’s try it by mapping babel-polyfill in main.js
require('babel-polyfill')
Copy the code
You read that correctly, is to be introduced in main.js, directly in the Webpack configuration does not seem to work.
After executing the package command, bundle.js is 194K in size, which is relatively small.
If you open the page in the browser, you will find the following error
Please click here for the cause and solution of this problem. Let’s modify the introduction of babel-polyfill by changing require to import, and promoting the introduction to the front
- require('babel-polyfill')
+ import 'babel-polyfill'
Copy the code
Pack it again
conclusion
Comparing the above three schemes, we draw the following conclusions
plan | Packaged size | advantages | disadvantages |
---|---|---|---|
babel-polyfill | 259K | Complete simulation of ES2015+ environment | Excessive volume; Contaminate global objects and built-in object prototypes |
babel-runtime | 63K | Introduction on demand, small packing volume | No instance methods are simulated |
Babel-preset -env (enable useBuiltIns) | 194K | Import on demand, high configurability | – |
There is no absolute advantages and disadvantages of the program, in the development process or flexible use according to the actual situation.
- Reference documentation
Do you really know how to use Babel?
babel-polyfill VS babel-runtime