最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • babel大揭秘

    正文概述 掘金(走秀)   2021-07-12   857

    babel分享

    babel介绍

    babel 是源码 => 源码的过程

      1. parse 代码 => ast
      2. transform 操作语法书 增删改 ast => ast (修改后的)
      3. generate 修改后的 ast => 新的代码
    
        抽象语法书 (Abstract Syntax Tree,AST)以树形结构表达 编程语言 的语法
    

    ast语法树 代码是从 经过词法分析 和 语法分析 最终生成ast 举一个例子 我是张三 词法分析的过程就相当于 张三 语法分析 一个赋值语句 张三 赋值给

    me = 'zhangsan' 词法分析过程最终生成结果 token (不能再拆分的单词) me、= 、'zhangsan' 语法分析的过程 发现 有一个等号(operator 操作符) 发现是赋值操作 left 是 me (标识符 identifierright 是 (字符串字面量 StringLiteral) 'xiaomenggang '

    1. 举个例子

    astexplorer.net/

    javascript:

        console.log(1)
    

    babel大揭秘

    babel大揭秘

    他的树形结构是这样的

    babel大揭秘

    ast 常见节点

    Statement 语句

    代码节点名称中文名
    forForStatement循环语句whileWhileStatementwhile语句continueContinueStatementcontinue语句SwitchSwitchStatementSwitch语句
    代码节点名称中文名
    var a = 'xmg';variableDeclaratio变量声明function fn(){}functionDeclaratio函数声明import d from 'e';importDeclaratio导出声明SwitchSwitchStatementSwitch语句
    代码节点名称中文名
    [1,2,3]ArrayExpression数组表达式a = 1AssignmentExpression赋值表达式1 + 2BinaryExpression二元表达式funciton () {}FunctionExpression函数表达式() => {}ArrowFunctionExpression箭头函数表达式

    超级微小编译器

    github.com/jamiebuilds…

    简单的从 词法分析 到 语法分析的一个简单实现过程

    我们先来看下babel 的api

    parse

    parse @babel/parser 将代码转换成 ast

    参数 pluginsouseTypescript script 则不解析 es module 语法 module 是解析 es module 语法 unambiguous 根据环境自动判断 )

    transform @babel/traverse 遍历AST 使用访问者 模式 对ast修改

    traverse(ast, visitor)

    visitor: {
      StringLiteral(path) {
        debugger
        console.log(path.node.value)
      }
    }
    

    path 上面有很多方法 比如 path.node 当前节点 比如 path.parent 获取父级节点 path.insertBefore 向前插入 path.repalceWith 替换 path.remove 删除 path.stop 停止遍历

    generate @babel/generate 将代码 从 ast 转成 code

    @babel/types 提供快速生成 ast 和 断言的方法 创建 ast和判断ast的节点类型 比如 types.IfStatement()

    if(1){}
    
      types.ifStatement(types.NumericLiteral(1),types.blockStatement([]))
    

    types.isIfStatement():boolean

    我们再来做一个例子 删除console代码

    const parser = require('@babel/parser');
    const traverse = require('@babel/traverse').default;
    const generate = require('@babel/generator').default;
    const types = require('@babel/types');
    
    
    // console.log(types.ifStatement(types.NumericLiteral(1),types.blockStatement([])))
    // console.log(generate(types.ifStatement(types.NumericLiteral(1),types.blockStatement([]))))
    
    const sourceCode = `
        console.log(1);
        function func() {
            var a = 2
            console.info(a);
        }
        export default class Clazz {
            say() {
                var b = 3
                console.debug(b);
            }
            render() {
                let bbb = 333
                console.log(bbb)
                return <div>{bbb}</div>
            }
        }
    `;
    
    const ast = parser.parse(sourceCode, {
        sourceType: 'unambiguous',
        plugins: ['jsx']
    });
    
    traverse(ast, {
        StringLiteral(path) {
            debugger
            console.log(path)
        },
        CallExpression(path) {
            // if(path.scope) {
            //     path.scope.generateUid('maidian')
            //     console.log(path.scope.generateUid('maidian'))
            // }
            // types.ifStatement
            if ( types.isMemberExpression(path.node.callee) 
                && path.node.callee.object.name === 'console' 
               ) {
                path.remove()
            }
        }
    });
    
    const { code, map } = generate(ast);
    console.log(code);
    

    我们再来做一个例子 实现代码混淆

    我们要说下 path 上的 scope 是作用域信息 生成作用域的就是模块、函数、块 作用域之间会形成嵌套关系,也就是作用域链

    scope.bindings 当前作用域内声明的所有变量

    const parser = require('@babel/parser');
    const traverse = require('@babel/traverse').default;
    const generate = require('@babel/generator').default;
    const types = require('@babel/types');
    let num=0;
    const string = `abcdefghigklsisysjsks`
    
    const sourceCode = `
        function getScr() {
            const num1 = 3
            const num3 = num1**num1
            const num5 = num3**num3
            function add () {
                return num5 + num3
            }
            const sum = add()
            return sum
        }
    `;
    
    const ast = parser.parse(sourceCode, {
        sourceType: 'unambiguous',
    });
    
    traverse(ast, {
        StringLiteral(path) {
            console.log(path)
        },
        Scopable(path, state) {
            if(path.scope.bindings) {
                Object.entries(path.scope.bindings).forEach(([key,binding] )=> {
                    binding.scope.rename(key,binding.scope.generateUid(string[num++]))
                })
            }
        }
    });
    
    const { code, map } = generate(ast);
    console.log(code);
    

    起源地下载网 » babel大揭秘

    常见问题FAQ

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

    发表评论

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

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

    联系作者

    请选择支付方式

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