Babel plug-in practice (II) Babel plug-in development

Ape_ Luck_ Boy 2021-09-15 09:45:13

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 .

2152694-ac88ce874fbfa3ae.webp

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

2152694-9183a48661f2e09c.webp

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

2152694-2c1aa974f90f44a9.webp

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

2152694-4804103cdeea4ccd.webp

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 !

Please bring the original link to reprint ,thank
Similar articles

2021-09-15