zoukankan      html  css  js  c++  java
  • bable

    Babel是一个javascrpt编译器,能将es6转换为es5代码。并且通过插件的形式可以灵活的扩展。

    从根目录读取.babelrc文件中读取配置。.babelrc是一个json文件

    配置

    • plugins
      babel-plugin-transform-runtime 要和 babel-runtime配合使用 减少多余的代码
    • presets 告诉babel要转换的源代码要使用那些新的语法特性,可以分为三大类。
      • 已经被ECMAscript标准里的特性
        • ES2015
        • ES2016
        • ES2017 2017年
        • Eev 包含所有特性
      • 被社区提出但未写入ECMAscript的特性
        • babel-preset-stage-0 仅仅是个想法
        • babel-preset-stage-1 提议
        • babel-preset-stage-2 草案
        • babel-preset-stage-3 候选
        • babel-preset-stage-4 已完成
      • 一些特定功能的react,flow react需要安装babel-preset-react
    • babel垫片 Babel 几乎可以编译所有时新的 JavaScript 语法,但对于 APIs 来说却并非如此。
      • babel-runtime 前者是手动挡 主要的功能是为api提供沙箱的垫片方案,不会污染全局的api
      • babel-plugin-transform-runtime 后者是自动挡
      • babel-polyfill
        babel-polyfill则是通过改写全局prototype的方式实现,比较适合单独运行的项目。开启babel-polyfill的方式,可以直接在代码中require,或者在webpack的entry中添加,也可以在babel的env中设置useBuildins为true来开启

    babel的polyfill和runtime的区别

    babel-polyfill 使用场景

    Babel 默认只转换新的 JavaScript 语法,而不转换新的 API。例如,Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局对象,以及一些定义在全局对象上的方法(比如 Object.assign)都不会转译。如果想使用这些新的对象和方法,必须使用 babel-polyfill,为当前环境提供一个垫片。

    思考:babel-runtime 为什么适合 JavaScript 库和工具包的实现?

    1. 避免 babel 编译的工具函数在每个模块里重复出现,减小库和工具包的体积;
    2. 在没有使用 babel-runtime 之前,库和工具包一般不会直接引入 polyfill。否则像 Promise 这样的全局对象会污染全局命名空间,这就要求库的使用者自己提供 polyfill。这些 polyfill 一般在库和工具的使用说明中会提到,比如很多库都会有要求提供 es5 的 polyfill。在使用 babel-runtime 后,库和工具只要在 package.json 中增加依赖 babel-runtime,交给 babel-runtime 去引入 polyfill 就行了;

    总结:

    1. 具体项目还是需要使用 babel-polyfill,只使用 babel-runtime 的话,实例方法不能正常工作(例如 "foobar".includes("foo"))
    2. JavaScript 库和工具可以使用 babel-runtime,在实际项目中使用这些库和工具,需要该项目本身提供 polyfill

    Babel 的处理步骤

    Babel 的三个主要处理步骤分别是:

    • 解析(parse)
    • 转换(transform)
    • 生成(generate)

    对应着babel-core源码中分别用到的babylon、babel-traverse、babel-generator

    (1)Babylon

    Babylon 是 Babel 的解析器。最初是 从Acorn项目fork出来的。Acorn非常快,易于使用。

    import * as babylon from "babylon";
    
    const code = `function square(n) {
      return n * n;
    }`;
    
    babylon.parse(code);
    // Node {
    //   type: "File",
    //   start: 0,
    //   end: 38,
    //   loc: SourceLocation {...},
    //   program: Node {...},
    //   comments: [],
    //   tokens: [...]
    // }
    
    (2)babel-traverse

    Babel Traverse(遍历)模块维护了整棵树的状态,并且负责替换、移除和添加节点。我们可以和 Babylon 一起使用来遍历和更新节点。

    import * as babylon from "babylon";
    import traverse from "babel-traverse";
    
    const code = `function square(n) {
      return n * n;
    }`;
    
    const ast = babylon.parse(code);
    
    traverse(ast, {
      enter(path) {
        if (
          path.node.type === "Identifier" &&
          path.node.name === "n"
        ) {
          path.node.name = "x";
        }
      }
    });
    
    (3)babel-generator

    Babel Generator模块是 Babel 的代码生成器,它读取AST并将其转换为代码和源码映射

    import * as babylon from "babylon";
    import generate from "babel-generator";
    
    const code = `function square(n) {
      return n * n;
    }`;
    
    const ast = babylon.parse(code);
    
    generate(ast, {}, code);
    // {
    //   code: "...",
    //   map: "..."
    // }
    

    抽象语法树(AST)

    ast抽象语法树在以上三个神器中都出现过,所以ast对于编译器来说至关重要。以下列举了一些ast的应用:

    • 浏览器会把js源码通过解析器转为抽象语法树,再进一步转化为字节码或直接生成机器码
    • JSLint、JSHint对代码错误或风格的检查,发现一些潜在的错误
    • IDE的错误提示、格式化、高亮、自动补全等等
    • UglifyJS
    • 代码打包工具webpack、rollup
    • CoffeeScript、TypeScript、JSX等转化为原生Javascript

    自己动手写插件

    基于babel-core在IDE中编写代码
    引用babel-core模块进行编码方式如下:
    
    ```
    const {transform,generate}=require('babel-core');
    const myPlugin=require('./myPlugin');
    
    const code = `d = a + b + c`;
    
    var es5Code = transform(code, {
      plugins: [myPlugin]
    })
    console.log(es5Code.code);
    ```
    
    ast explorer https://astexplorer.net/

    编写babel插件之前先要理解抽象语法树这个概念。编译器做的事可以总结为:解析,转换,生成。具体的概念解释去看入门手册可能会更好。这里讲讲我自己的一些理解。

    解析包括词法分析与语法分析。

    解析过程吧。其实按我的理解(不知道这样合适不合适= =)抽象语法树跟DOM树其实很类似。词法分析有点像是把html解析成一个一个的dom节点的过程,语法分析则有点像是将dom节点描述成dom树。

    转换过程是编译器最复杂逻辑最集中的地方。首先要理解“树形遍历”与“访问者模式”两个概念。

    结合树形遍历来看,就是说每个访问者有进入、退出两次机会来访问一个节点。

    而我们这个替换常量的插件的关键之处就是在于,访问节点时,通过识别节点为我们的目标,然后替换他的值!

  • 相关阅读:
    python 集合
    jQuery选择器
    hdu 5747 Aaronson
    hdu 2049 不容易系列之(4)——考新郎
    hdu 2048 神、上帝以及老天爷
    hdu 2045 不容易系列之(3)—— LELE的RPG难题
    hdu 2047 阿牛的EOF牛肉串
    hdu 2046 骨牌铺方格
    hdu 2050 折线分割平面
    hdu 2044 一只小蜜蜂
  • 原文地址:https://www.cnblogs.com/chenjinxinlove/p/8467759.html
Copyright © 2011-2022 走看看