Preface
The last article talked about babel
Compilation principle and process , This article is officially written babel
plug-in unit . If the babel
If the compilation principle and process are not clear, please see the previous article babel Plug in practice ( One )babel Compilation principle analysis
@babel/core
As can be seen from the name, this is babel
The core of the package . First of all, let's introduce this package , This package integrates the @babel/parser
,@babel/traverse
,@babel/generator
,@babel/types
These bags . In other words, the package has the ability to parse (parse
), transformation (traverse
), The ability to generate code , It also extends other functions .
Have a look first @babel/core
Of package.json file ,@babel/core Of package.json, As shown in the figure below, these packages are built in , It also integrates other babel
package , Other packages can understand their role .
This article mainly uses babel/core
To demonstrate , So you need to know the commonly used api
, Please click here @babel/core Commonly used api
To write babel plug-in unit
babel Plug in specifications
In fact, write babel
Plug in is simple , Just write the code according to the official rules ok 了 . Official documents
You can see from the picture above , To write your own plug-in, you need to provide a method for the plug-in by default , This method returns a containing visitor
Object of property .visitor
It's also an object , The object attribute supports hook functions corresponding to different node types , Operate on this type of node in this function .( That is, in the previous article, we mentioned that when the node is traversed in depth in the conversion step , The hook function provided )
According to the official tips , Try it yourself .
Create an empty project as described in the previous article ( The same formula , The same taste ), establish build/index.js
, install @babel/core
plug-in unit ,
To write build/index.js
The code is as follows :
const babel = require("@babel/core")
const code = `
class Person {
constructor(name){
this.name = name
}
say(){
console.log(this.name)
}
}
const person = new Person(" Zhang San ");
person.say()
`
const obj = babel.transformSync(code, {
plugins: [
function MyPlugin(babel) {
return {
visitor: {
Identifier(path) {
console.log(path.type, path.node.name)
}
}
}
}
]
});
console.log(obj.code);
Copy code
@babel/core
Of transformSync
Method second parameter , You can pass in plugins
Array , Here you can set your own plug-in ; Is it very simple . As for what plug-ins do , You need to decide for yourself .
The above is just a trial ( The written plug-in is not separated from a separate file ). The following is to modify the compiled code , Read the source code from the file instead , as follows
const babel = require("@babel/core")
const path = require("path");
const file = path.resolve(__dirname, './../src/index.js');
const obj = babel.transformFileSync(file, {
plugins: [
function MyPlugin(babel) {
return {
visitor: {
Identifier(path) {
console.log(path.type, path.node.name)
}
}
}
}
]
});
console.log(obj.code);
Copy code
transformFileSync
Is to read compiled code from a file . What is specified above is from src/index.js
File read .
From the above, I know clearly babel
How plug-ins work . Analyze... From a code perspective , In fact, that is babel/core
Provided api
There is one plugins
Configuration properties , It only supports the introduction of custom plug-ins .
Separate the plug-in
In front-end projects ,babel
All plug-ins appear as independent modules . Now .babelrc
Configuration files come in handy .transformFileSync
The second parameter object has a babelrc
attribute , The default is true
. This attribute represents whether to read from the project root babelrc
File acquisition presets
and plugins
To configure .
Next, create... In the project root directory my-babel-plugin/index.js
file , In this file, you are solely responsible for the plug-in functions . Put it on top build/index.js
The plug-in code moves here , The code is as follows :
module.exports = function (babel) {
return {
visitor: {
Identifier(path) {
console.log(path.type, path.node.name)
}
}
}
}
Copy code
build/index.js
The code is as follows :
const babel = require("@babel/core")
const path = require("path");
const file = path.resolve(__dirname, './../src/index.js');
const obj = babel.transformFileSync(file, {
babelrc: true
});
console.log(obj.code);
Copy code
.babelrc
The file configuration is as follows :
{
"plugins": [
"./my-babel-plugin/index.js"
]
}
Copy code
By this time, we have babel
The plug-in is pulled out alone . If you want to publish to npm
On , You just need to follow the release specifications and steps , Then install it , stay .babelrc
Configuration is OK .
The careful little friend found , The source code to compile is es6
Of class
grammar , But the compiled code doesn't change . We talked about it before babel/core
In fact, it only provides the compilation process . If you want to process code , You also need to provide plug-ins ( In the second part of the compilation transform) Add, delete, modify and query nodes , Only then can the node be modified to generate the final desired executable code . It is because of babel
The official provides rules for customizing plug-ins , To produce the present rich babel
Plug in Ecology .
Here, if you need to deal with es6
And above , Need to use babel/preset-env
Preset package ( Is a collection of plug-ins ), Install the package , modify .babelrc
To configure
{
"presets": [
"@babel/preset-env"
],
"plugins": [
"./my-babel-plugin/index.js"
]
}
Copy code
Perform compilation at time , You can see the output process on the console babel/preset-env
Processed code , Here's the picture
From the above compilation results , You can also learn more about es6
Of class
Translate it into es5
What is the code like , Those who are interested can learn about it .
babel plug-in unit Demo Development
The plug-in we wrote above has no function , It just introduces the pre steps of developing a custom plug-in , Now let's implement a delete console
Code plug-ins .
First step : First, determine the node type you want to operate , Understand the characteristics of nodes . Here we analyze online console.log(123)
Corresponding ast
node . You can see that the yellow part represents this line console.log(123)
node . as follows
The second step : Write custom plug-in code , Go straight to the code , as follows
module.exports = function (babel) {
return {
visitor: {
Identifier(path) {
console.log(path.type, path.node.name);
},
CallExpression(path) {
if(path.node.callee && babel.types.isIdentifier(path.node.callee.object, {name: 'console'})){
path.remove();
}
}
}
}
}
Copy code
As can be seen from the figure above, this expression corresponds to CallExpression
Node of type , This node has a callee
Property corresponds to MemberExpression
Node of type ,MemberExpression
The node has another object
The attribute is Identifier
Node of type , Only Identifier
The node name is console
Only then can we judge that the current node is console
Expression of type . And then execute path.remove
Method to delete the current node .
above bable.types
The corresponding is @babel/types
Plug-in package , When the plug-in executes, it will be passed in as a parameter , The functions of this package have been discussed in the last article .( When developing plug-ins, this provides api
It's used a lot , So it's very important ).
Compile again , You'll find that console.log/error/warn
In the compiled code, they are removed accordingly .
babel
This concludes the plug-in practice series , thank you !