Develop a Babel plug-in

This article is a VsCode editor for the tutorial, if your editor is not VsCode then this article debugging methods you will not be able to use.

** What does this plugin do? **

  • This is a plugin that automatically adds properties to React components.

** 2, if we achieve the effect? **

  • 1. Add properties to React components
  • 2. Can debug code using VsCode breakpoints
  • 3, can use the shortcut command automatically package TS

Note: I didn’t write the code in babel-project/index.ts, it’s the code for babel-plugin-react-auto-props. The purpose of this article is to show you how to use VSCode for development and debugging, and to open the door to Babel plug-in development. The entire project directory structure:

 .vscode 
   --launch.json // vscode debugs configuration files
   --task.json // Automatically package the configuration
 babel-project
   --index.ts // Project code
 dist // Project packaged file
   --index.js
   --index.js.map
 lib // The converted code for our plug-in
   --index.js
 node_modules
 test // Test the directory
   --index.js
 babel.config.js // Babel configuration file
 package.json
 package-lock.json
 tsconfig.json // ts configuration file
Copy the code

Packages that need to be used (some packages are not used, just know) :

  • @babel/cli
  • @babel/preset-react
  • @babel/core
  • @babel/generator
  • @babel/template
  • @babel/traverse
  • @babel/traverse
  • @babel/traverse
  • @babel/types
  • babylon
  • @babel/preset-env

Step 1 (Create a directory)

  • Start by creating a new directorynpm initAfter init, create these subdirectories in this directory
 .vscode
   --launch.json
   --task.json
 babel-project
   --index.ts
 test
   --index.js
Copy the code
  • Then NPM I * * -d above the last package

Part 2 (Configuration Files)

tsconfig.json

We need to configure typescript with rootDir, outDir, what module type do we need to package target code into, etc.

{
  "compilerOptions": {
      "baseUrl": "."."paths": { "*": ["types/*"]},"module": "commonjs"."target": "es6"."outDir": "./dist"."lib": ["es6"."dom"]."sourceMap": true."rootDir": "babel-project"
  },
  "include": [
    "babel-project/**/*"]."exclude": ["node_modules"]}Copy the code

.vscode/launch.json

This is the VsCode configuration file. We point the program parameter to babel-cli’s index.js and add the parameter setting entry and exit

{
  "version": "0.2.0"."configurations": [{"type": "node"."request": "launch"."name": "Start program"."sourceMaps": true."program": "${workspaceFolder}/node_modules/@babel/cli/lib/babel/index.js"."args": [
        "test/index.js"."-o"."lib/index.js"]]}}Copy the code

.vscode/task.json

This is the build command configuration file for VsCode. With this configured we can package our project code using shortcut keys

{
  "version": "0.1.0 from"."command": "tsc"."isShellCommand": true."args": ["-p"."."."-w"]."showOutput": "always"."problemMatcher": "$tsc"
}
Copy the code

babel.config.js

This is our plug-in configuration file. If someone uses this plug-in in the future, this is what they’re going to configure

const presets = ['@babel/preset-react']

const plugins = [
  [
    './dist/index.js',
    {
      "Button": {
        "size": "small"}}]]module.exports = { presets, plugins }

Copy the code

package.json

Project dependency file configuration, this needless to say

. "scripts": { "build": "tsc" }, .....Copy the code

The test code

This is the code we will use to test the plug-in, and we will package this code as we want

let b = <PPP>1234</PPP>
let element = <Button color="red"  />
Copy the code

babel-project/index.ts

Here comes the ontology ~ this is all the code for our plug-in.

// import * as babelCore from '@babel/core'
import * as parser from '@babel/parser'
import * as types from '@babel/types'
import traverse, { NodePath } from '@babel/traverse'

export default function() {
    return {
        visitor: {
            CallExpression(path: NodePath<types.CallExpression>, state) {
                // return if is not React call createElement expression
                let { callee } = path.node
                let b = 3;
                if (
                    !(
                        types.isMemberExpression(callee) &&
                        types.isIdentifier(callee.object) &&
                        callee.object.name === 'React' &&
                        types.isIdentifier(callee.property) &&
                        callee.property.name === 'createElement')) {return
                }

                // get the component type name and it's extra props options
                let [element, propsExpression] = path.node.arguments
                let elementType: string
                if (types.isStringLiteral(element)) {
                    elementType = element.value
                } else if (types.isIdentifier(element)) {
                    elementType = element.name
                }

                const options: Object = state.opts
                let extraProps: Object | undefined = options[elementType]

                if(! extraProps) {return
                }

                // build the extra props ObjectExpression
                let stringLiteral = JSON.stringify(extraProps)
                let extraPropsExpression = parser.parseExpression(stringLiteral)

                // if the default props is null(empty)
                if (types.isNullLiteral(propsExpression)) {
                    path.node.arguments[1] = extraPropsExpression
                } else if (types.isObjectExpression(propsExpression)) {
                    path.node.arguments[1] = types.objectExpression(
                        propsExpression.properties.concat(
                            (<types.ObjectExpression>extraPropsExpression).properties,
                        ),
                    )
                }
            },
        },
    }
}
Copy the code

Step 3 (Package test)

  • According to theCtrl + Shift + BSelect NPM: Build to wrap up our project code.

  • inbabel-project/index.tsTo add a breakpoint anywhere, press F5

After the final execution is our plug-in modified code

lib/index.js

let b = /*#__PURE__*/React.createElement(PPP, null."1234");
let element = /*#__PURE__*/React.createElement(Button, {
  color: "red"."size": "small" // This is added by our plugin
});
Copy the code

Well, reading this doesn’t teach you how to develop a Babel plug-in, only how to debug a simple Babel plug-in.