摘要:是一个对象,它表示两个节点之间的连接。接着返回一个对象,其属性是这个插件的主要节点访问者。所以上面的执行方式是运行引入了自定义插件的打包文件现在为明显减小,自定义插件成功插件文件目录觉得好玩就关注一下欢迎大家收藏写评论
目录
Babel简介
Babel运行原理
AST解析
AST转换
写一个Babel插件
Babel简介Babel 是一个 JavaScript 编译器,它能将es2015,react等低端浏览器无法识别的语言,进行编译。
上图的左边代码中有箭头函数,Babel将进行了源码转换,下面我们来看Babel的运行原理。
Babel运行原理Babel 的三个主要处理步骤分别是:
解析(parse),转换(transform),生成(generate)。.
其过程分解用语言描述的话,就是下面这样:
解析
使用 babylon 解析器对输入的源代码字符串进行解析并生成初始 AST(File.prototype.parse)
利用 babel-traverse 这个独立的包对 AST 进行遍历,并解析出整个树的 path,通过挂载的 metadataVisitor 读取对应的元信息,这一步叫 set AST 过程
转换
transform 过程:遍历 AST 树并应用各 transformers(plugin) 生成变换后的 AST 树
babel 中最核心的是 babel-core,它向外暴露出 babel.transform 接口。
let result = babel.transform(code, { plugins: [ arrayPlugin ] })
生成
利用 babel-generator 将 AST 树输出为转码后的代码字符串
AST解析AST解析会把拿到的语法,进行树形遍历,对语法的每个节点进行响应的变化和改造再生产新的代码字符串
节点(node)AST将开头提到的箭头函数转根据节点换为节点树
ES2015箭头函数
codes.map(code=>{ return code.toUpperCase() })
AST树形遍历转换后的结构
{ type:"ExpressionStatement", expression:{ type:"CallExpression" callee:{ type:"MemberExpression", computed:false object:{ type:"Identifier", name:"codes" } property:{ type:"Identifier", name:"map" } range:[] } arguments:{ { type:"ArrowFunctionExpression", id:null, params:{ type:"Identifier", name:"code", range:[] } body:{ type:"BlockStatement" body:{ type:"ReturnStatement", argument:{ type:"CallExpression", callee:{ type:"MemberExpression" computed:false object:{ type:"Identifier" name:"code" range:[] } property:{ type:"Identifier" name:"toUpperCase" } range:[] } range:[] } } range:[] } generator:false expression:false async:false range:[] } } } }
我们从 ExpressionStatement开始往树形结构里面走,看到它的内部属性有callee,type,arguments,所以我们再依次访问每一个属性及它们的子节点。
于是就有了如下的顺序
进入 ExpressionStatement 进入 CallExpression 进入 MemberExpression 进入 Identifier 离开 Identifier 进入 Identifier 离开 Identifier 离开 MemberExpression 进入 ArrowFunctionExpression 进入 Identifier 离开 Identifier 进入 BlockStatement 进入 ReturnStatement 进入 CallExpression 进入 MemberExpression 进入 Identifier 离开 Identifier 进入 Identifier 离开 Identifier 离开 MemberExpression 离开 CallExpression 离开 ReturnStatement 离开 BlockStatement 离开 ArrowFunctionExpression 离开 CallExpression 离开 ExpressionStatement 离开 Program
Babel 的转换步骤全都是这样的遍历过程。(有点像koa的洋葱模型??)
AST转换解析好树结构后,我们手动对箭头函数进行转换。
对比两张图,发现不一样的地方就是两个函数的arguments.type
let babel = require("babel-core");//babel核心库 let types = require("babel-types"); let code = `codes.map(code=>{return code.toUpperCase()})`;//转换语句 let visitor = { ArrowFunctionExpression(path) {//定义需要转换的节点 let params = path.node.params let blockStatement = path.node.body let func = types.functionExpression(null, params, blockStatement, false, false) path.replaceWith(func) // } } let arrayPlugin = { visitor } let result = babel.transform(code, { plugins: [ arrayPlugin ] }) console.log(result.code)
注意: ArrowFunctionExpression() { ... } 是 ArrowFunctionExpression: { enter() { ... } } 的简写形式。
Path 是一个对象,它表示两个节点之间的连接。
定义需要转换的节点
ArrowFunctionExpression(path) { ...... }
创建用来替换的节点
types.functionExpression(null, params, blockStatement, false, false)
babel-types文档链接
在node节点上找到需要的参数
replaceWith(替换)
写一个Babel插件从一个接收了 babel 对象作为参数的 function 开始。
export default function(babel) { // plugin contents }
接着返回一个对象,其 visitor 属性是这个插件的主要节点访问者。
export default function({ types: t }) { return { visitor: { // visitor contents } }; };
我们日常引入依赖的时候,会将整个包引入,导致打包后的代码太冗余,加入了许多不需要的模块,比如index.js三行代码,打包后的文件大小就达到了483 KiB,
index.js
import { flatten, join } from "lodash"; let arr = [1, [2, 3], [4, [5]]]; let result = _.flatten(arr);
所以我们这次的目的是将
import { flatten, join } from "lodash";
转换为从而只引入两个lodash模块,减少打包体积
import flatten from "lodash/flatten"; import join from "lodash/join";
实现步骤如下:
在项目下的node_module中新建文件夹 babel-plugin-extraxt
注意:babel插件文件夹的定义方式是 babel-plugin-插件名
我们可以在.babelrc的plugin中引入自定义插件 或者在webpack.config.js的loader options中加入自定义插件
在babel-plugin-extraxt新建index.js
module.exports = function ({types:t}) { return { // 对import转码 visitor:{ ImportDeclaration(path, _ref = { opts: {} }) { const specifiers = path.node.specifiers; const source = path.node.source; // 只有libraryName满足才会转码 if (_ref.opts.library == source.value && (!t.isImportDefaultSpecifier(specifiers[0]))) { //_ref.opts是传进来的参数 var declarations = specifiers.map((specifier) => { //遍历 uniq extend flatten cloneDeep return t.ImportDeclaration( //创建importImportDeclaration节点 [t.importDefaultSpecifier(specifier.local)], t.StringLiteral(`${source.value}/${specifier.local.name}`) ) }) path.replaceWithMultiple(declarations) } } } }; }
修改webpack.prod.config.js中babel-loader的配置项,在plugins中添加自定义的插件名
rules: [{ test: /.js$/, loader: "babel-loader", options: { presets: ["env","stage-0"], plugins: [ ["extract", { "library":"lodash"}], ["transform-runtime", {}] ] } }]
注意:plugins 的插件使用顺序是顺序的,而 preset 则是逆序的。所以上面的执行方式是extract>transform-runtime>env>stage-0
运行引入了自定义插件的webpack.config.js
打包文件现在为21.4KiB,明显减小,自定义插件成功!~
插件文件目录
YUAN-PLUGINS | | - node_modules | | | | - babel-plugins-extract | | | index.js | | - src | | - index.js | | - webpack.config.js觉得好玩就关注一下~欢迎大家收藏写评论~~~
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/93831.html
摘要:的工作过程的处理主要过程解析转换生成。代码转换处理,处理工具插件等就是在这个阶段进行代码转换,返回新的。若感兴趣了解更多内容,插件中文开发文档提供了很多详细资料。 Babel简介 Babel是Javascript编译器,是种代码到代码的编译器,通常也叫做『转换编译器』。 Babel的工作过程 Babel的处理主要过程:解析(parse)、转换(transform)、生成(generat...
摘要:最近的技术项目里大量用到了需要修改源文件代码的需求,也就理所当然的用到了及其插件开发。在这里我要推荐一款实现了这些标签的插件,建议在你的项目中加入这个插件并用起来,不用再艰难的书写三元运算符,会大大提升你的开发效率。具体可以参见插件手册。 最近的技术项目里大量用到了需要修改源文件代码的需求,也就理所当然的用到了Babel及其插件开发。这一系列专题我们介绍下Babel相关的知识及使用。 ...
摘要:继个实例入门并掌握二后续配置配置配置使用加快打包速度多页面打包配置编写编写编写十七配置源码地址本节使用的代码为基础我们来模拟平时开发中,将打包完的代码防止到服务器上的操作,首先打包代码然后安装一个插件在中配置一个命令运 继 24 个实例入门并掌握「Webpack4」(二) 后续: PWA 配置 TypeScript 配置 Eslint 配置 使用 DLLPlugin 加快打包速度 多...
摘要:表示的是在严格模式下解析并且允许模块定义即能识别和语法识别不了。 前段时间开始研究ast,然后慢慢的顺便把babel都研究了,至于ast稍后的时间会写一篇介绍性博客专门介绍ast,本博客先介绍一下babel的基本知识点。 背景: 由于现在前端出现了很多非es5的语法,如jsx,.vue,ts等等的格式和写法,如果要在浏览器的设备上识别并执行,需要额外将这些非传统格式的语法转成传统的es...
摘要:而扫描各个模块并合并路由表的脚本非常简单,读写文件就了。编写插件之前先要理解抽象语法树这个概念。的解析器,的配置。编写脚本识别字段思路首先获取到源代码是类单文件的语法。获取内的字段,并替换成已生成的路由表。 话不多说先上图,简要说明一下干了些什么事。图可能太模糊,可以点svg看看showImg(https://segmentfault.com/img/bV3fs4?w=771&h=63...
阅读 3597·2021-11-24 10:22
阅读 3667·2021-11-22 09:34
阅读 2451·2021-11-15 11:39
阅读 1495·2021-10-14 09:42
阅读 3647·2021-10-08 10:04
阅读 1511·2019-08-30 15:52
阅读 794·2019-08-30 13:49
阅读 2996·2019-08-30 11:21