What’s a Babel?
Babel is a compilerAt a macro level, the compilation process of a compiler is generally divided into three steps
- Parsing the original code into an abstract syntax tree (AST)
- Transforming the AST of the first step to get a new AST
- Generating (also called printing) traverses the new AST to generate object code
Parsing is divided into two steps
- Lexical analysis, which is the breaking down of raw code into tokens (objects that describe the smallest independent syntactic units)
- Syntax analysis, recursive traversal of tokens array, and construction of AST
Take a chestnut
While the above description may seem a bit abstract, let’s walk through the input and output of these three steps with a practical example.Let’s say we want to convert lisp code on the left to C code on the right. Let’s take a look at what the input and output of each step look likethe-super-tiny-compilerI strongly recommend myself to implement again, the code is not much, remove the comments only more than 200 lines, comments are very detailed, very easy to understand).
1.1 Lexical analysis
As shown above, the main function of this step is to parse our input code (a bunch of strings) into tokens, which are objects that describe a single syntactically unit, such as parentheses, numbers, function names, identifiers, etc.
1.2 Grammar Analysis
Take the array of tokens in the first step and generate an abstract syntax tree (AST) through recursive processing. If you want to know how the JS code we usually write will be converted into ast by Babel, you can check the following websiteastexplorer
2 Ast Transformation (Transforming)
In this step, the syntax tree obtained in the grammar analysis stage is transformed into the desired syntax tree by adding, deleting and modifying the syntax tree. Of course, no transformation is possible for our simple example (we can generate code directly from the AST based on parsing), but this is for demonstration purposes only.
Generating object code
This step prints out the string (our object code) by directly recursively processing the abstract syntax tree.
Does the example above give us a clearer picture of how the compiler compiles source code into object code? Now that we understand the process, let’s look at how Babel organizes these processes.
As shown above, babel-Parser is responsible for converting input code to ast, and babel-traverse is responsible for providing deep traversal of AST nodes. (Traverse itself is not responsible for converting ast, only providing traversal of AST nodes. The specific conversion logic is handed over to a variety of Babel plug-ins, which also greatly improves the expansibility of Babel. If new language features are added in the future, there is no need to modify or rarely modify the core code, but only need to write corresponding plug-ins to convert the new syntax. For example, @babel/plugin-transform-arrow-functions is used to transform arrow functions), and babel-generator is responsible for printing object code according to the new AST.
The core concept
The plug-in
The Babel initial case does not do any transformations to the code, and the Babel workflow is shown below
code => babel= > code
Copy the code
Since Babel doesn’t initially convert code, how did we write es6 code to become ES5? The answer is plugins. With Babel-traverse, plugins can traverse ast nodes and add, delete, change, and change code. The reason for the adoption of plug-in architecture should be for functional separation, easy extension and maintenance.
preset
The granularity of the plug-in itself is very fine, so that each syntax may have its own plug-in for transformation. For example, the arrow functions in ES6 are transformed by @babel/plugin-transform-arrow-functions. It can be annoying if so many preset plug-ins need to be introduced and configured manually, so Babel abstruses preset to manage a set of plug-ins, which is more user-friendly, and is usually just used for preset using @babel/ PRESET -env.
Core packages
@babel-core
Contains @babel/parser, @babel/traverse, and @babel/ Generator. The Parser parses the source code into an AST, and the traverse provides the ability to traverse the AST nodes. The Generator is responsible for generating object code from the transformed AST.
@babel/cli
Provides the ability to call @babel/core from the command line.
@babel/runtime & @babel/plugin-transform-runtime
Babel inserts some helper functions at the top of the module as it transforms code, for example:
class A {}
Copy the code
The above code may (depending on the environment we are supporting) become the following code when compiled by Babel
'use strict';
function _classCallCheck(instance, Constructor) {
if(! (instanceinstanceof Constructor)) {
throw new TypeError('Cannot call a class as a function'); }}var A = function A() {
_classCallCheck(this, A);
};
Copy the code
The _classCallCheck is called the help function, and by default Babel will type the help function directly into the target file, as we did here. If we have a lot of modules, this type of help directly into the target file will cause the output code to grow to some extent. A better approach might be to take an introduction approach. The @babel/runtime and @babel/ plugin-transform-Runtime do just that. Specific use is as follows:
- Install dependencies
Babel /runtime contains a variety of helper functions, which are needed when the code is running.
# We here as production dependency import
npm i @babel/runtime;
Copy the code
npm i -D @babel/plugin-transform-runtime
Copy the code
- configuration
babel.config.js
const config = {
// Other configurations
plugins: ['@babel/plugin-transform-runtime']};module.exports = config;
Copy the code
The transform code is shown below
'use strict';
var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault');
var _classCallCheck2 = _interopRequireDefault(
require('@babel/runtime/helpers/classCallCheck'));var A = function A() {(0, _classCallCheck2.default)(this, A);
};
Copy the code
You can see that _classCallCheck2 has been imported from @babel/ Runtime
The resources
- Dissect Babel — Take one small step forward for the architect
- The -super-tiny-compiler (excellent material for understanding how compilers work, only 200 + lines of code after removing comments, highly recommended to implement it yourself)