教你如何编写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 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插件时再也不用慌了(๑•̀ㅂ•́)و✧
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
勇敢新世界‧互聯網罪與罰
許煜、劉細良 / CUP / 2005 / $48
我天天上網數小時,為的是要在節目裡面介紹世界的最新動態,尤其是網絡這個世界本身日新月異的變化。所以我不可能不注意到BT、共享軟件、 Wikipedia、網絡監管等各種影響政治、社會、經濟及文化的重要網絡現象。但是我發現市面上一直沒有一本內容充實全面,資料切時的中文參考書,直到這本《互聯網罪與罰》。而且,最大的驚喜是它易讀好看,簡直就像故事書。 梁文道 鳳凰衛視 《網羅天下......一起来看看 《勇敢新世界‧互聯網罪與罰》 这本书的介绍吧!