教你如何编写Babel插件

栏目: JavaScript · 发布时间: 5年前

内容简介:前置知识:了解babel的使用,了解JavaScript语法树 安装我们的打包文件

前置知识:了解babel的使用,了解JavaScript语法树 安装 babel-cli, babel-core

我们的打包文件

import antd, { Table } from 'antd';

let arrow = () => {};
const component = <Table />;
复制代码

.babelrc 配置

{
  "presets": ["react"],
  "plugins": [
    [
      "lessimport", //这是你开发的plugin名称,包名命名为babel-plugin-xxxx
      {
        // 这些属性可以随意,最后可以在opts里面访问得到
        "libraryName": "antd",
        "modulePath": "/lib/{moduleName}",
        "styleSuffix": "css",
        "stylePath": "/lib/{moduleName}/style/index.{styleSuffix}"
      }
    ]
  ]
}
复制代码

插件代码编写

这是进行转换操作的代码,在你新建的项目node_modules下面新建babel-plugin-lessimport文件夹 新建index.js,写入以下代码

const babel = require('babel-core');
const type = require('babel-types');

const visitor = {
  ImportDeclaration(path, ref = { opts: {} }) {
    const specifiers = path.node.specifiers;
    const source = path.node.source;
    const libraryName = source.value;
    /**
     * 第二个判断条件是判断import语句里面有没有使用 import {xxx} 的语法,如果有,就替换
     * 不加这个条件的后果就是,死循环
     */
    if (libraryName === ref.opts.libraryName && specifiers.find(specifier => type.isImportSpecifier(specifier))) {
      const declarationNodes = [];
      specifiers.forEach(specifier => {
        /** 不是默认导入的
         *  为什么要这么判断,因为可能会有这种写法,import React, { Component } from 'react';
         */
        if (!type.isImportDefaultSpecifier(specifier)) {
          declarationNodes.push(
            /**
             * importDeclaration 第一个参数是import xxx from module 里面的xxx
             * xxx可以是 {yyy} => [importSpecifier], yyy => [importDefaultSpecifier], 空 => []
             * 第二个参数是module字符串
             */
            type.importDeclaration(
              // 添加一个默认导入的 specifier,可以多个,这样就是import xxx, yyy from "test"
              [type.importDefaultSpecifier(specifier.local)],
              // type.stringLiteral 返回一个字面量字符串
              type.stringLiteral( // {moduleName} 是在配置里面配置的,代表需要引入模块的名字
                `${libraryName}${ref.opts.modulePath.replace('{moduleName}', specifier.local.name.toLowerCase())}`
              )
            )
          );
          // 引入css 或者 less,可配置
          if (ref.opts.styleSuffix) {
            declarationNodes.push(
              type.importDeclaration(
                [], // 空的specifier, 这样就是 import from "xxxx"
                type.stringLiteral(
                  `${libraryName}${ref.opts.stylePath
                    .replace('{moduleName}', specifier.local.name.toLowerCase())
                    .replace('{styleSuffix}', ref.opts.styleSuffix)}`
                )
              )
            );
          }
          return;
        }
        declarationNodes.push(
          type.importDeclaration([type.importDefaultSpecifier(specifier.local)], type.stringLiteral(libraryName))
        );
      });
      // 一个节点替换成多个
      path.replaceWithMultiple(declarationNodes);
    }
  },
  /**
   * 转换箭头函数很简单,直接把id, 参数,函数体,是否generator,是否async函数都赋给新函数
   * 然后替换节点即可
   */ 
  ArrowFunctionExpression(path) {
    const node = path.node;
    if (node.type === 'ArrowFunctionExpression') {
      path.replaceWith(type.functionExpression(node.id, node.params, node.body, node.generator, node.async));
    }
  },
  /**
   * 把let, const转换成var 
   */
  VariableDeclaration(path) {
    const node = path.node;

    if (node.kind === 'let' || node.kind === 'const') { 
      // 变量声明的kind, 可以是var let const
      // 然后第二个参数是声明的变量,let a, b, c这里的a, b, c就是node.declarations
      const varNode = type.variableDeclaration('var', node.declarations);
      path.replaceWith(varNode);
    }
  },
};
module.exports = function() {
  // 名称必须是visitor
  return { visitor };
};
复制代码

第一个 Node 是 source 的值,第二个是 specifiers 的值 你也可以去astexplorer看对应的语法树(网址在文末给出)

教你如何编写Babel插件

执行,查看插件转换效果

对代码执行

babel index.js --out-file out.js
复制代码

转换后的代码为,说明转换成功了

import antd from 'antd';
import Table from 'antd/lib/table';
import 'antd/lib/table/style/index.css';

var arrow = function (x = 5) {
  console.log(x);
};

var component = React.createElement(Table, null);
复制代码

看到这就要恭喜你啦,再也不用写这种啰里啰嗦,打包出来文件体积还大的代码了

import {Table} from "antd";
import from "antd/lib/table/style/index.css";
复制代码

使用插件后只需要第一句即可完成按需引入和自动引入css 还可以配置多个不同的库

以后面试当面试官问你你写过babel插件时再也不用慌了(๑•̀ㅂ•́)و✧


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

游戏的设计与开发

游戏的设计与开发

次世代工作室 / 人民交通出版社 / 2003-12 / 50.00元

一起来看看 《游戏的设计与开发》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

随机密码生成器
随机密码生成器

多种字符组合密码

SHA 加密
SHA 加密

SHA 加密工具