三分钟带你学会 自定义 Babel 插件

最近在做自动国际化,用到了babel的插件, 所以为了减小自动国际化的篇幅,就把这部分单独提出来,目的是为了能让小白都能看懂babel插件的真实面目。

babel插件

babel的编译流程:

主要分为三步,流程主要为:

parsing(解析)、transforming(转化)、generating(生成)

  1. parsing: 它使用@babel/parser库, 负责将es6代码进行语法分析和词法分析后转换成抽象语法树AST
  2. transforming: plugin插件利用 @babel/traverse库来,来遍历AST节点,操作他们,用它提供的 API 来编写对AST的遍历和修改逻辑,由此来将一种AST转换为另一种AST
  3. generating:``@babel/generator负责将处理后的 AST树 生成 新的 es5 代码

Plugins 和 Presets 的运行顺序

  • Plugins 在 Presets 前运行
  • Plugins 顺序从前往后排列
  • Presets 顺序是颠倒的(从后往前)

推荐一个写插件好用的AST语法树结构工具,在写插件的时候,你不要知道他的type到底是什么,就可以用这个工具帮你查询。

AST抽象语法树结构网站: AST Explorer

babel编译文件

  1. 引入babel:npm install --save-dev @babel/cli

  2. 在src/index.js文件里面写一个函数

js 复制代码
const fn = () => {
  console.log('hello babel')
}

3.用babel编译 执行命令

js 复制代码
npx babel src --out-dir lib

结果

我想编译某一个文件就写这样:

js 复制代码
 npx babel src/index.js --out-dir lib
  npx babel src/app.js --out-dir lib

在lib下面就会出现编译后的具体的文件。

babel插件实现

现在我们写一个插件,希望把具体index.js里面 ceshi 的函数名改成test,把你的函数copyAST Explorer里面,然后点一下 ceshi 函数名,就会出现对应的 AST结构。

其实babel插件就是一个函数,把这个函数接入到babel的配置文件中,它就会自动执行。所以在plugin/index.js文件里面导出一个函数就好了。

在return里面导出一个编译器对象,它包含一个visitor属性,它里面包含了我们要操作的内容,比如在上图,我们看到函数名的结构是:Identifier, 那么咱们的插件就变成了这样的,顺便在控制台打印下path.name看看

创建babel.config.js文件,引入插件

执行命令:

js 复制代码
npx babel src/index.js --out-dir lib

发现

写一下插件业务

js 复制代码
module.exports = function () {
  return {
    visitor: {
      Identifier(path) {
        let name = path.node.name;
        if (name === 'ceshi') {
          console.log(path.node)
          path.node.name = 'test'
        }
      },
    },
  };
}

执行npx babel src/index.js --out-dir lib查看结果:

你看一个小小的babel插件就搞定了,我想打包发布到npm上,然后在其他包里面使用怎么办?

babel插件发布npm

npm login输入用户名和密码,报错code 403

因为源地址应该是淘宝的,所以安装 npm 管理器:nrm,之前有个nvm是node版本管理器,现在出来个nrm,专门管理npm的源地址:

js 复制代码
npm i nrm -g
nrm ls
nrm use npm

你要想看看现在用的是哪个镜像源,就执行下nrm ls,或者 npm config get registry

现在再登陆

js 复制代码
npm login

在发布之前,一定要创建一个文件是.npmignore 在这个文件里面写上你不需要发布的文件比如:

在发布之前,要对代码进行打包,在npm里面的文件一般都是处理以后的文件,这样publish的时候体积比较小,使用的时候才快。一般工具库打包都用的rollup,一般应用型项目才会用webpack和vite。

js 复制代码
npm i rollup -D

创建配置文件:

package.json scripts里配置命令:

执行打包

js 复制代码
npm run build

执行发布

js 复制代码
npm publish

它会把你项目下面所有的东西都发布到npm上去,在发布过程中,我发现我的项目名字和别人的重复了,发布不上去,我就改了项目要名叫:babel-plugin-change-name1

备注:在打包的时候,请一定要将代码统一掉,要么全部是ESM 的,要么是commonjs的。我的项目采用的ESM,在package.json里面配置type:module就好了。当然 rollup 默认支持ESM,你要是想要打包commonJS的就要用插件了。所以没有必要这么做。我们只需要将工具包和使用包全部默认是ESM 就不会出现不必要的bug。

检查发现工具代码里面有commonJS的导出,所以赶紧改改,再次打包,发布即可。

测试babel插件

在另外一个项目里面安装测试下看看

js 复制代码
npm i babel-plugin-change-name1 -D

执行babel编译命令报错

说明这个vite应用默认支持commonJS,需要在package.json里面配置

把babel插件里面的测试文件拿过来,然后再咱们的项目里面执行npx babel src/index.js --out-dir lib查看结果:

终于把ceshi 改成了 test 是不是?

很明显这样不合理,我们一般都是执行打包的时候,babel才去执行的,现在是用一个命令在执行,我们想办法把他配到webpack或者vite里面去,当执行npm run build 的时候,babel自动处理代码。

babel接入打包工具webpack、vite

vite集成babel

js 复制代码
安装
pnpm i vite-plugin-babel @babel/core -D
  1. 然后进入vite.config.ts文件中使用babel插件,并且将 build.target 设置为es2015 即可
js 复制代码
import vue from '@vitejs/plugin-vue'
import babel from "vite-plugin-babel";
import vueJsx from '@vitejs/plugin-vue-jsx'

export default defineConfig({
  base: './',
  plugins: [
    babel(),
    vue(),
    vueJsx(),
    // 其他插件...
  ],
  build: {
    target: 'es2015'
  }
})

webpack5 集成babel

安装

js 复制代码
npm install -D babel-loader @babel/core @babel/preset-env

webpack.config.js配置

js 复制代码
module: {
  rules: [
    {
      test: /\.?js$/,
      exclude: /node_modules/,
      use: {
        loader: 'babel-loader'
      }
    }
  ]
}

babel.config.json配置

js 复制代码
{
  "presets": [
    ["@babel/preset-env", {
      "targets": "> 0.25%, not dead"
    }]
  ],
  "plugins": [
    // 不污染全局,在运行时加载
    ["@babel/plugin-transform-runtime", {
      "corejs": 3
    }]
  ]
}

接入我们的项目

我们只需要引入babel-loader就好了,具体babel的配置放到babel.config.js里面,这样做的好处是webpack的配置文件不会庞大而繁杂,难以阅读和修改。

执行打包

js 复制代码
npm run dev

发现报错了,只要 package.json 文件里面写 type:module 那么所有的文件都要用 ESM

改完以后,打包正常

js 复制代码
npm run build

此时你发现他成功了,但是你用index.html引入测试下看看

打开页面

因为打包的时候用了sourcemap,我们对应的是本地源码,他已经帮我们略过了中间环节,测试的时候,用npx babel src/index.js --out-dir lib测试通过,就没有问题。

整个自定义babel插件流水线全部结束,希望您能和我一样有所收获。

总结:

  • 插件名称必须是babel-plugin-xxx

  • .babelrc可以添加你的插件以及配置参数

  • 插件编写必须遵循规范

  • 当你想改变某个节点时,使用该节点名(首字母大写)称作为函数名进行访问,使用path.replaceWith或者repalceWithMultiple替换

参考文章:

babel中文文档

# 前端工程化基石 -- AST(抽象语法树)以及AST的广泛应用🔥

babel-types: 官网

babel-handbook: Babel 手册

ast-explorer: AST 可视化

es-tree JavaScript 语法树规则

相关推荐
崔庆才丨静觅10 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606111 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了11 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅11 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅11 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅11 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment12 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅12 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊12 小时前
jwt介绍
前端
爱敲代码的小鱼12 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax