Babel was originally called 6to5, which, as the name suggests, was es6 going ES5. As we know, there is an ES release every year, with ES7 (ES2016), ES8 (ES2017), and so on. Obviously, 6to5’s name was no longer appropriate, so 6to5 was renamed Babel.
A reference to the Tower of Babel:
At that time, men were united to build a tower that they hoped would lead to heaven. In order to stop their plan, God made them speak different languages, so that they could not communicate with each other. This event provides an explanation for the emergence of different languages and races in the world. This tower is the Tower of Babel.
This reference to The Tower of Babel fits the position of Babel’s translator.
Babel compilation process
The purpose of Babel has been clear from the beginning to the present, which is to translate the new syntax and API in the source code into target browser support. It adopts the micro-kernel architecture, the whole process is relatively streamlined, and all the transformation functions are completed by plug-ins.
Parse converts source code into an AST, transform converts an AST into object code, and generate sourcemap.
In the Transform phase, various built-in plug-ins are applied to complete the transformation of the AST. The transformation done by the built-in plug-in consists of converting unsupported syntax to a syntax supported by the target environment to achieve the same function, and automatically introducing the corresponding polyfill for the unsupported API.
The compilation process and purpose of Babel have never changed, but the way to accomplish this purpose has. Let’s review how Babel 6 and 7 were designed, and what Babel 8 will do to help you understand Babel.
babel 6
The ES standard is a yearly release, which means that Babel plugins need to follow up in real time, implementing a series of plugins a year.
There is also a process for new syntax and APIS to be introduced into the ES standard, which is divided into several stages:
- Phase 0 – Strawman: Just an idea, possibly implemented with the Babel Plugin
- Stage 1 – Proposal: A Proposal worth continuing
- Phase 2 – Draft: Creating a spec
- Phase 3 – Candidate: Complete the spec and implement it in the browser
- Phase 4 – Finished: Will be added to the es20XX Spec next year
With so many features to Babel to transform, each feature is done with a Babel plug-in. But there are a lot of features, that is to say, a lot of presets, so you can’t let the user configure each of the presets themselves, so Babel 6 introduces the concept of PRESET, a set of plugins.
If we want to use es6 syntax we’ll use babel-preset- ES2015, ES7 is introducing babel-preset- ES2016 and so on. If you want to use features not included in the standard, use babel-preset- Stage0, babel-preset- Stage1, etc. So by selecting a different preset, plus manually introducing some presets, that’s what all Babel will do.
You can think of this as the union of sets.
The result of the union is all the supported features.
In this way, Babel 6 supports the configuration of various feature transformations that are not supported by the target environment.
If you think about it, is there a problem with that?
Although this can achieve the goal, but there are problems, mainly in two points:
-
The es standard is changing every year, the current Stage-0 might be stage-2 soon, what about preset maintenance, should it change, how do users know what features this Stage-X supports?
-
It can only be converted to ES5, and the target environment supports some ES6 features, so are these conversions and polyfills useless? And it also increases the volume of the product.
-
Polyfill manual introduction, more troublesome, is there a better way
These two problems were always present in Babel 6. So it’s a pass, but it’s a problem, so let’s give it a 70. (60 points will be given if the function is complete, 10 points more is a preset introduced for Babel 6, which really simplifies a lot of configurations)
So what’s the solution to Babel 6? Babel 7 provides the answer.
babel 7
Babel 7 has changed a lot. For example, all packages have been moved to @babel scope, which is @babel/ XXX. We don’t care about that.
Babel 7 disuses the preset packages of PRESET -20xx and PRESET -stage-x, and replaces them with PRESET -env. Preset -env supports all es standard features by default, and is no longer packaged as preset if not included in standard. You need to specify plugin-proposal-xxx manually.
Its set looks like this:
Is it easier than Babel 6?
(Preset -react is not the ES standard syntax and has not changed much, so it is not included).
But the change of preset and plugin proposals only solves the problem of previous preset changing frequently. So how is this problem solved by converting some of the features supported by the environment?
The answer is compat-table, which provides the minimum supported version of each feature in different browsers or Node environments, and Babel maintains a database based on this, under @babel/ Compat-data.
There is data on which versions of each feature are supported in different environments:
With this data, the user can specify what the target environment is. In this case, you can write a browserslist query like last 1 version, > 1%. Babel uses Brwoserslist to convert them to the target environment specific version of the data.
With the lowest version of the data for the environment supported by the different features, and with the specific version, filter out the features that are not supported by the target environment, and then introduce their corresponding plug-ins. That’s what preset-env does.
Configuration methods are as follows:
{
"presets": [["@babel/preset-env", { "targets": "> 0.25%, not dead." "}}]]Copy the code
This solves the problem of converting the features already supported by the target environment through preset-env. Polyfills can also be filtered through targets.
Polyfills are no longer introduced manually, so how? Of course it’s introduced automatically with preset-env. However, this function is not enabled by default. It needs to be configured.
{
"presets": [["@babel/preset-env", {
"targets": "> 0.25%, not dead." "."useBuiltIns": "usage".// or "entry" or "false"
"corejs": 3}}]]Copy the code
Configure Corejs and useBuiltIns.
-
Corejs is the polyfill used by Babel 7, and corejs 3 does not support polyfill for instance methods such as array.prototype.fill until the version is specified.
-
UseBuiltIns is the way to use polyfill (Corejs), whether to import all entries, the usage per file, or not (false).
With these two options configured, polyfills are automatically introduced.
Polyfill is imported globally by default. Sometimes you need to use @babel/ plugin-transform-Runtime to avoid polluting global variables. This plugin is available in Babel 6.
Instead of polluting the global environment, it is introduced with a unique identifier.
It looks like the Babel 7 is perfect enough to score in the 90s.
No, Babel 7 has a Babel 7 problem.
Babel 7 problem
– @babel/ plugin-transform-Runtime does not support configuring targets because it does not know what the target environment supports, so it can only do all the transformations. Student: You might say isn’t there a preset env?
The application order of plugins in Babel is: Plugin first and then preset, plugin left to right, preset right to left, so plugin-transform-runtime is before preset-env.
After the @babel/ plugin-transform-Runtime conversion is finished, give the preset-env to the preset-env because the useless conversion has been made.
Let’s try it out:
Let’s take a look at the environment support for array.prototype. fill:
As you can see, this feature is supported in Chrome 45 and above, but not in Chrome 44.
Let’s try preset-env separately:
When specifying targets as Chrome 44, polyfill should be automatically introduced:
When specifying targets as Chrome 45, you do not need to introduce polyfill:
The results are as expected, 44 in, 45 not in.
Let’s try @babel/plugin-transform-runtime:
Chrome 45 supports the array.prototype. fill method.
I asked the author about the feature request, and the author said that the latest @babel/polyfills would solve the problem.
I went to have a look, and this bag is still in the experimental phase, and it does solve that problem.
This package is expected to be built into Babel in Babel 8.
So give Babel 7 a score, the introduction of preset-env allows us to use more accurate conversion code and polyfill, I wanted to give 90 points, but the plugin-transform- Runtime problem made me give it 10 points less, and give 80 points overall.
babel 8
Babel 8 isn’t out yet, but we know that any updates to Babel will be based around the main line, which is to automate precise transformations and polyfills for features not supported by the target environment. Babel 8 solves the @ Babel/Polyfills problem that Babel 7 left over from @babel/ plugin-transform-Runtime. Targets can now be used to accurately introduce polyfills on demand.
It supports the configuration of a Polyfill provider, which means you can specify Corejs2, Corejs3, es-shims, and other polyfills, and you can also customize polyfil, which means you can use your own polyfill.
Then, once you have the polyfill source, using the polyfill method also builds in what the transform-Runtime did before, from the previous useBuiltIns: entry, useBuiltIns: 2. The usage of the dictionary became 3.
- Entry-global: This compares to useBuiltIns: Entry, which introduces polyfills globally.
- Usage-entry: This, compared with useBuiltIns: Usage, is the polyfill that specific modules introduce for use.
- Usage-pure: This is what the transform-Runtime plug-in was supposed to do, using pure to introduce the polyfill for the specific module without polluting the global variable.
Babel 7 supports all three of these as well, but no plug-ins are needed now, and the Polyfill Provider configuration is supported, so @babel/preset-env is fully functional by Babel 8.
How can the plug-in use targets if it wants to use them?
Since I have been writing the Babel Plugin Tutorial recently, I was concerned about the impact on the plugin. I asked the Babel maintainer if he should inject the plugin into the API when @babel/core calls the plugin so that the plugin can get targets.
I asked this in the morning. In the afternoon, I was surprised to find that the Babel document was supplemented with the @babel/ Helper-compile-targets document. Helper is a way to reuse code between plug-ins, which is a library for plug-in development.
This library provides three apis:
- Query the target environment version: getTargets
- Filter the target environment: filterItems
- Determine whether a plug-in needs: isRequired
This corresponds to the three phases we discussed earlier, where you need to first query the target environment, then filter the target environment, and then determine whether a plug-in is needed.
The plugin uses api.targets() to get the environment configuration and uses isRequired to determine if a plugin is necessary.
As a result, targets are perfectly supported in both the built-in plugin and PRESET implementations, as well as the API available for the plug-in, and targets is really integrated into Babel at this stage.
Babel at this stage, I think we can give a score of 90:
Supports polyfill and transform according to the configured target environment, supports switching and customization of polyfill, the configuration is simple enough, targets can also be used in the plug-in, and provides a convenient helper package.
Babel development law
Babel 8 is still on the way, but we can already see a glimpse of what it will look like. The core idea of Babel has not changed since its inception. The original name, 6to5, was to transform or polyfill syntax and apis that were not supported in the target environment. As accurate as possible, as simple as possible in configuration, and as easy to write plug-ins can do more.
So for this purpose, Babel developed a preset (Babel 6), preset-env (Babel 7), polyfill Provider (Babel 8), Plugin-transform-runtime (Babel 6), etc.
There are more and more apis, helpers and so on that plug-ins can use.
Babel continues to evolve, but its purpose and nature remain the same. We are going to learn something, but we are also going to learn it by grasping its essence, so I have written a little book called “Babel Plugin Secrets” (coming soon) to help you “finish” Babel!