Open oakland opened 4 years ago
https://babeljs.io/docs/en/babel-preset-env#modules 看 webpack tree shaking 的时候看到这个配置方式 这个其实就是配置 babel 以什么模块方式去转换 es module 的模块
generate 生产出的代码是 unicode 的格式,需要添加一个配置项:
"generatorOpts": {
"jsescOption": {
"minimal": true
}
}
path.skip() 很重要,参考如下:
最近打算写一篇和 babel 相关的文章,好像也没有什么说的,主要就是用法,如何写一个插件,以及原理。如何写一个插件算是中级水平,其实也没有什么,就是一些深入的 api。最深入的内容就是原理部分,就涉及到 AST 和 编译器 相关的内容。作为入门的话,其实先写到原理的 AST 部分就够了。再往深入其实已经不是 babel 了,就是编译器和解释器。可以考虑和 sicp 结合者一起写。如何写插件其实也比较简单,主要是思路,用法很简单。
@babel/core VS babel-core
最近做 TIP 的时候打算用一个新的 babel plugin:babel-plugin-proposal-optional-chaining,按照 npmjs 中的安装方式安装完发现编译时候出错,无法找到 plugin。后来看了下,发现 babel 从 version7.x 之后就采用另外一种安装方式了。原来是 babel-core,后来是 @babel/core 的方式。然后 google 搜了下“babel-core vs @babel/core”,看到了一些相关的内容。 what-is-the-difference-between-babel-core-and-babel-core,这里面引用一段话
v7-migration#scoped-packages,官网给出的内容
how-to-upgrade-to-babel-7 给出了一种比较傻瓜的升级方式:
presets VS plugins
difference-between-plugins-and-presets-in-babelrc
其实 presets 就是 plugins 的集合,就是已经帮你组装好了,你直接用就行了,不需要你自己组合 plugins 了。
plugins 和 presets 的顺序
plugin-ordering
This means if two transforms both visit the "Program" node, the transforms will run in either plugin or preset order.
Plugins run before Presets. Plugin ordering is first to last. Preset ordering is reversed (last to first).
先执行插件,然后执行 presets,插件的顺序是从左到右,而 presets 的执行顺序是从右向左。
这个部分的例子也很好,也说了为什么 presets 要 reverse order。是
AST
AST 是有 Node 组成的,Node 其实就是拥有 type 属性和其他必要属性,能描述清楚当前节点的 Object。其中 type 属性是必须的。 每个 Node 都有 type 属性,用来表示这个 node 的类型,同时还拥有其他属性,用来描述这个 Node,比如 function 除了 type 之外,就还拥有 id, params, body 三个属性用来描述 function。
同理,二元操作符通过如下属性就可以进行完整的描述:
对于简单的字符串和数字,则通过 type 和 value 两个字段就可以表达完整。例如
'hello'
和1
用 Node 表示分别是:babel-types
上面说了 AST 会有很多 Node,每个 Node 都是一个 type,那每个 type 能干什么呢?babel-types 发挥作用了。babel-types 可以判断一个 Node 是否是某个 type,也可以构建一个 Node,例如:
具体每个 type 怎么生成,以及怎么判断,就去 官网 看文档。
除了判断一个 Node 的类型之外,可能还需要判断这个 Node 的其他属性,例如可以通过下面的方式判断一个 二元表达式的左节点是否是 Identifier 且命名为
n
:@babel/parser
@babel/core
用来转换代码? https://babeljs.io/docs/en/next/options
@babel/generator
astexplorer
可以在本地预览 ast,ast github 仓库地址 https://github.com/fkling/astexplorer,克隆下来,本地启动服务做实验。
useBuiltIns and @babel/polyfill
https://babeljs.io/docs/en/babel-polyfill#size
plugin 中的 path
写 plugin 的时候,肯定会用到 path,那么 path 到底是个什么东西呢? plugin-handbook中有一段描述。
就是说 path 就是一个很大的对象,可以直接修改,并且可以获取两个 node 之间的关联关系。
path 其实就是包含了当前节点的所有信息的对象,同时还拥有很多方法可以更新当前节点。
path.node
就是当前节点,path.parent
就是当前节点的父级节点。这两个属性一定会有,通常感觉用到的最多的也是这两个属性。用到的比较多的方法就是path.traverse
,示例也可以看上面 plugin-handbook 中的示例。babel-core-apidoc
https://npmdoc.github.io/node-npmdoc-babel-core/build/apidoc.html 这里面有很多相关的 api 说明,而且都是以函数的方式表达出来的。 比如这里面就有我一直不太理解的 scope.maybeGenerateMemoised(node),打开之后跳转到这里,里面写了这个函数到底是干什么的,好像是判断静态节点还是动态节点的。
plugin-proposal vs plugin-syntax
transform-plugin-vs-syntax-plugin-in-babel
也就是说 plugin-syntax 仅仅让 babel 可以解析这个新的语法,而 plugin-proposal 是可以让这种语法转化成 es5。
在深入浅出 Babel 上篇:架构和原理 + 实战中也说到了关于 syntax plugin 的问题:
作者:荒山 链接:https://juejin.im/post/6844903956905197576 来源:掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
optional-chaning 详解
是时候学习/推广一波可选链(Optional chaining)和空值合并(Nullish coalescing )了
上面这篇文章里的这两点解答了我心中的一些疑惑。
精读《Optional chaining》 上面这篇文章也很好,非常详细的解释了 optional-chaining 这个提案,看起来一个很简单的功能其实背后有很多复杂的逻辑和设计思想。
一些可以参考的简单 babel 插件
babel原理及插件开发
https://juejin.im/post/6844904038438273032
babel-plugin-playground 可以在线编写 babel 插件实现转换
https://juejin.im/post/6844903582613897223 Babel 在提升前端效率的实践 写个 Babel 插件丰富你的 console 内容
understanding-asts-building-babel-plugin 这篇文章提供了一个很好的写插件的方式,就是先把变化前后的 ast 用图的方式表达出来,然后就可以很方便的分析了。
https://github.com/babel/generator-babel-plugin,没用过,应该是写复杂插件的时候再用吧?
非常好的参考文章
深入浅出 Babel 上篇:架构和原理 + 实战,这篇文章除了 babel 之外把很多扩展的东西也说了。
看 @babel/parser 源码看到了一些奇怪的数字表达
在 mdn 上找到了答案,https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Numbers_and_dates,以
0b
开头的表示 binary number。如何看 tokens
通过 astexploer 可以看到解析后的 tokens,如下图