最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 手把手实现一个babel的插件及了解一下AST

    正文概述 掘金(estar_rocky)   2021-03-20   845

    babel插件

    本文主要有以下几个内容

    • 为什么要实现一个插件
    • 实现插件所需要的知识
    • 如何去实现
    • 业务中有可能需要用到的

    为什么要实现一个插件

    想知道多一点

    实现插件所需要的知识

    • 一点点的AST知识
      1. AST基本讲解及参数
      2. AST的在线编译工具
    • 一点点的编译原理知识以及babel的编译过程
      • 编译原理
      • babel及AST文档
    • 一点点的英文阅读能力@babel/types。开发的过程中需要用到babel的类型,需要了解它的类型接使用方法

    如何去实现

    这里简单实现一个可选操作链的babel

    • 新建一个空文件夹
    • npm install --save-dev @babel/core @babel/cli
    • .gitignore .babelrc.json
      • .gitignore node_modules
      • .babelrc.json
          {
          "plugins": [
                "./plugins/optional-chaining-plugin" // 我们开发插件位置
            ]
          }
        
    • src/index.js
        // 要编译的内容
        function demo(foo) {
          return foo?.bar;
        }
      
    • ok,重头戏来了,开始去编写转换规则 plugins/optional-chaining-plugin

    编写转换规则

    1. 了解babel的作用
      • babel主要是将高版本的js或者是非js或json的文件转换成js,方便浏览器识别并运行
    2. babel的转换过程
    • 转换过程

      1. 解析(parse)
      • 接收代码并转换成AST结构
        • 两步
          1. 词法分析
          • 词法分析阶段把字符串形式的代码转换为 令牌(tokens)
            你可以把令牌看作是一个扁平的语法片段数组:
            n * n
            
              [
                { type: { ... }, value: "n", start: 0, end: 1, loc: { ... } },
                { type: { ... }, value: "*", start: 2, end: 3, loc: { ... } },
                { type: { ... }, value: "n", start: 4, end: 5, loc: { ... } },
                ...
              ]
            
            每一个 type 有一组属性来描述该令牌:
              {
                type: {
                  label: 'name',
                  keyword: undefined,
                  beforeExpr: false,
                  startsExpr: true,
                  rightAssociative: false,
                  isLoop: false,
                  isAssign: false,
                  prefix: false,
                  postfix: false,
                  binop: null,
                  updateContext: null
                },
                ...
              }
            
            和 AST 节点一样它们也有 startendloc 属性。.
          1. 语法分析
          • 语法分析阶段会把一个令牌流转换成 AST 的形式。 这个阶段会使用令牌中的信息把它们转换成一个 AST 的表述结构,这样更易于后续的操作。
      1. 转换(transform)
      • 对生成的AST结构进行添加,更新及移除操作
      1. 生成(generator)
      • 把转换后的AST转换成字符串形式的代码,同时还会创建源码映射(source)
    1. 要编译的内容转成浏览器兼容的是什么样的 babel在线转换
    • 原写法
      function demo(foo) {
        return foo?.bar;
      }
    
    • 浏览器兼容
      function demo(foo){
        return foo == null ? void 0 : foo.bar
      }
    
    1. 查看新旧代码的AST结构
    • 访问astexplorer.net/
    • 开始编写代码 babel plugin 组件模板
        module.exports = function (babel) {
          const {
            types: t,
            template
          } = babel
          return {
            name: 'my-plugin',
            visitor: {
              // expression 表达式
            }
          }
        }
      
    • 由于我们这里是处理可选操作符,所以我们去查阅文档 @babel/types,得出可选操作是optionalMemberExpression
      module.exports = function (babel) {
        const {
          types: t,
          template
        } = babel
        return {
          name: 'my-plugin',
          visitor: {
            // expression 表达式
            optionalMemberExpression(path) {
              const {object, property} = path.node
    
              // path为当前遍历的节点,这个节点为命中可选操作符的内容,即 foo?.bar ,我们需要将这个节点替换
              path.replaceWith(
                // 这里我们就要开始写替换后的内容了,把 foo == null ? void 0 : foo.bar 拿过来比对
                // 每一个表达式都要创建,如何去创建。babel自带的types已经为我们封装了所有表达式,直接调用即可
                // 首先是三元运算符  xxx ? xxx : xxx,照旧去文档寻找三元运算符的表达式 https://www.babeljs.cn/docs/babel-types#conditionalexpression  t.conditionalExpression(test, consequent, alternate)
                // 三个入参, test consequent alternate 。不知道是啥咋办,没关系。把这段代码 foo == null ? void 0 : foo.bar 放入 ast 去转译。就能在右侧的asttree下看到你想要的东西,包括 test consequent alternate。
                t.ConditionalExpression( // 构造三元运算符
    
                  // 构造三元运算符问好左边内容
                  t.BinaryExpression( // https://www.babeljs.cn/docs/babel-types#binaryexpression 
                    '==',
                    t.identifier(object.name), // https://www.babeljs.cn/docs/babel-types#identifier
                    t.nullLiteral(), // https://www.babeljs.cn/docs/babel-types#nullliteral
                  ),
    
                  //  三元运算符冒号左边内容
                  t.UnaryExpression( // https://www.babeljs.cn/docs/babel-types#unaryexpression
                    "void",
                    t.numericLiteral(0) // https://www.babeljs.cn/docs/babel-types#numericliteral
                  ),
                  // 三元运算符冒号右边内容
                  t.MemberExpression( // // https://www.babeljs.cn/docs/babel-types#memberexpression 
                    t.identifier(object.name),
                    t.identifier(property.name),
                  )
                )
              )
            }
          }
        }
      }
    

    t.conditionalExpressionast 效果

    手把手实现一个babel的插件及了解一下AST
    优化,其实我们可以用babeltemplate来优化下写法 @babel/template

      t.UnaryExpression(
        "void",
        t.numericLiteral(0)
      ),
      // 改变为
      template.expression('void 0')(),
    
    1. 搞定,然后执行 yarn start "start": "babel src/ -d dist/"。编译后代码就出现在dist中了

    业务中用到的场景

    暂时还没发现.....期待各位大佬补充

    所需插件的知识进阶

    • 访问者模式
    • 更深的编译原理理解
    • 数据结构与算法

    文章参考

    • Babel插件开发入门指南
    • Babel for ES6? And Beyond!
    • Babel 插件手册
    • 手把手带你入门 AST 抽象语法树
    • 为什么要了解AST
    • Babylon-AST初探-代码更新&删除(Update & Remove)

    起源地下载网 » 手把手实现一个babel的插件及了解一下AST

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元