We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
对于babel,相信没有哪个前端不知,它是当下前端开发的标配,可以让我们提早使用es6/7/8等新的js特性。它将使用最新标准编写的js代码向下编译使之能在各个浏览器中运行,实现源码到源码的编译。 本文主要介绍一些babel的基础,毕竟有了基础,才能熟练的使用或者编写出babel的插件,同时编写一个很是easy的babel的插件。
babel
源码到源码
easy
它允许用户在命令行中编译js代码,可以直接运行 babel index.js,来编译js文件:
babel index.js
--out-file
-o
--watch
-w
--source-maps
sourceMap
presets
plugins
.babelrc
package.json
babel的核心功能就在这个包中,例如 transform 方法,这样我们就能在代码中直接使用编程的方式来转化js代码,实现形如组件库中代码的组件代码的预览功能。
transform
babel的解析器,生成babel的ast树:
const parser = require('@babel/parser'); const code = `function square(n) { return n * n; }`; parser.parse(code);
它也接受一些配置项,如:
true
super
jsx
用于遍历ast树,同时负责替换,移除或者添加节点,可以根据各个节点的不同类型,做一些不同的事
babel的工具库,可以帮助我们了解ast的构造变换或者验证,编写babel插件免不了与他打交道。 该模块拥有每一个单一类型节点的定义,包括节点包含哪些属性,什么是合法值,如何构建节点、遍历节点,以及节点的别名等信息。babel Definitions
将ast 转化为代码并生成sourceMap:
const generate = require('@babel/generator').default; const ast = { type: 'Program', start: 0, end: 38, body: [ { type: 'FunctionDeclaration', start: 0, end: 38, id: { type: 'Identifier', start: 9, end: 15, name: 'square', }, expression: false, generator: false, params: [ { type: 'Identifier', start: 16, end: 17, name: 'n', }, ], body: { type: 'BlockStatement', start: 19, end: 38, body: [ { type: 'ReturnStatement', start: 23, end: 36, argument: { type: 'BinaryExpression', start: 30, end: 35, left: { type: 'Identifier', start: 30, end: 31, name: 'n', }, operator: '*', right: { type: 'Identifier', start: 34, end: 35, name: 'n', }, }, }, ], }, }, ], sourceType: 'module', }; const { code } = generate(ast); console.log(code); // output: /* function square(n) { return n * n; } */
这个类似于模板替换,将模板中的字符串转化为指定值:
const template = require('@babel/template').de; const generate = require('@babel/generator').default; const t = require('@babel/types'); const buildRequire = template(` var IMPORT_NAME = require(SOURCE); `); const ast = buildRequire({ IMPORT_NAME: t.identifier('myModule'), SOURCE: t.stringLiteral('my-module'), }); console.log(generate(ast).code); // var myModule = require("my-module");
相当于一个帮你封装了plugins以及另外的presets的简便操作,省的你要将babel的配置到处重写一遍,它是从后往前执行的,区别于plugin的从前往后执行,简单看下babel-preset-react中的配置:
从后往前
plugin
从前往后
babel-preset-react
import { declare } from "@babel/helper-plugin-utils"; import transformReactJSX from "@babel/plugin-transform-react-jsx"; import transformReactDisplayName from "@babel/plugin-transform-react-display-name"; import transformReactJSXSource from "@babel/plugin-transform-react-jsx-source"; import transformReactJSXSelf from "@babel/plugin-transform-react-jsx-self"; export default declare((api, opts) => { api.assertVersion(7); const pragma = opts.pragma || "React.createElement"; // 当编译jsx表达式的时候使用的替换函数 const pragmaFrag = opts.pragmaFrag || "React.Fragment"; // 当编译 JSX fragments 时使用的替换组件 const throwIfNamespace = opts.throwIfNamespace === undefined ? true : !!opts.throwIfNamespace; const development = !!opts.development; const useBuiltIns = !!opts.useBuiltIns; if (typeof development !== "boolean") { throw new Error( "@babel/preset-react 'development' option must be a boolean.", ); } return { plugins: [ [ transformReactJSX, { pragma, pragmaFrag, throwIfNamespace, useBuiltIns }, ], transformReactDisplayName, development && transformReactJSXSource, development && transformReactJSXSelf, ].filter(Boolean), }; });
可以看出,该preset内置了plugin-transform-react-jsx,plugin-transform-react-display-name插件,同时在开发环境中内置了 plugin-transform-react-jsx-source 和 plugin-transform-react-jsx-self
plugin-transform-react-jsx
plugin-transform-react-display-name
plugin-transform-react-jsx-source
plugin-transform-react-jsx-self
好了介绍了一些基础知识,就该来编写一个插件了。 之前在项目开发的时候,经常要在代码中写debugger来打断点,但写着写着,很容易忘记把这些debugger给注释或者删除,所以我们来写一个删除debugger的babel plugin
debugger
我们先来看看,有debugger时的代码其ast树是如何的:
可以看见,在ast中存在一个 DebuggerStatement类型的节点,当我们把该debugger注释或者删除之后,看下其ast类型是如何的: 所以,该插件只要把该节点给删除了就好了,下面是直接加一个文件中演示的结果,可以看见,它返回结果是把debugger给删除了:
DebuggerStatement
看起来OK,接着我们将其在实际项目中试试,babel的插件必须以 babel-plugin-* 开头,同时由于该插件是转化了代码,所以我们就将其命名为 babel-plugin-transform-remove-debugger:
babel-plugin-*
babel-plugin-transform-remove-debugger
module.exports = function(babel){ return { visitor:{ DebuggerStatement(path, state) { // 用户的配置项可以通过state来获取 path.remove(); }, } } }
我们直接在create-react-app中看看效果:
create-react-app
class App extends Component { clickImage = () => { debugger; console.log('点击了'); }; render() { return ( <div className="App"> <button onClick={this.clickImage}>点我</button> </div> ); } }
将我们的插件配置其中: 在点击按钮的时候可以看见,并没有出现断点,所以我们的插件是ok的,至此我们就完成了一个插件,是不是很简单??后面当我想把该插件发布的时候,发先npm上已经有一个了,这就勾起了我的好奇心,想知道实现上有何不同,果然实现思路都是一样,就多了一个命名与严格模式,哈哈。
关于babel,自己还会继续深入学习,看看其他著名的插件是如何实现的,并会做记录。
下面的 Babel 用户手册和 Babel 插件手册是干货,读完之后你会更加深刻学习到babel的内部,同时如何更好的实现一个plugin
Babel 用户手册
Babel 插件手册
Babel 用户手册 Babel 插件手册 从零开始编写一个babel插件
The text was updated successfully, but these errors were encountered:
No branches or pull requests
对于
babel
,相信没有哪个前端不知,它是当下前端开发的标配,可以让我们提早使用es6/7/8等新的js特性。它将使用最新标准编写的js代码向下编译使之能在各个浏览器中运行,实现源码到源码
的编译。本文主要介绍一些babel的基础,毕竟有了基础,才能熟练的使用或者编写出
babel
的插件,同时编写一个很是easy
的babel的插件。babel的一些常用包简介
babel-cli
它允许用户在命令行中编译js代码,可以直接运行
babel index.js
,来编译js文件:--out-file
或者-o
来指定编译后的输出文件--watch
或者-w
来进行实时编译--source-maps
来生成sourceMap
此外还能将
presets
,plugins
等写在命令行中,但并不推荐,最好使用.babelrc
或者在package.json
中的babel字段babel-core
babel的核心功能就在这个包中,例如
transform
方法,这样我们就能在代码中直接使用编程的方式来转化js代码,实现形如组件库中代码的组件代码的预览功能。babel-parser
babel的解析器,生成babel的ast树:
它也接受一些配置项,如:
true
,那么你可以写在任何一个允许声明的地方super
jsx
语法编译babel-traverse
用于遍历ast树,同时负责替换,移除或者添加节点,可以根据各个节点的不同类型,做一些不同的事
babel-types
babel的工具库,可以帮助我们了解ast的构造变换或者验证,编写babel插件免不了与他打交道。
该模块拥有每一个单一类型节点的定义,包括节点包含哪些属性,什么是合法值,如何构建节点、遍历节点,以及节点的别名等信息。babel Definitions
babel-generator
将ast 转化为代码并生成sourceMap:
babel-template
这个类似于模板替换,将模板中的字符串转化为指定值:
presets与plugins
presets
相当于一个帮你封装了
plugins
以及另外的presets
的简便操作,省的你要将babel的配置到处重写一遍,它是从后往前
执行的,区别于plugin
的从前往后
执行,简单看下babel-preset-react
中的配置:可以看出,该preset内置了
plugin-transform-react-jsx
,plugin-transform-react-display-name
插件,同时在开发环境中内置了plugin-transform-react-jsx-source
和plugin-transform-react-jsx-self
好了介绍了一些基础知识,就该来编写一个插件了。
之前在项目开发的时候,经常要在代码中写
debugger
来打断点,但写着写着,很容易忘记把这些debugger
给注释或者删除,所以我们来写一个删除debugger的babel plugin我们先来看看,有
debugger
时的代码其ast树是如何的:可以看见,在ast中存在一个
DebuggerStatement
类型的节点,当我们把该debugger注释或者删除之后,看下其ast类型是如何的:所以,该插件只要把该节点给删除了就好了,下面是直接加一个文件中演示的结果,可以看见,它返回结果是把
debugger
给删除了:看起来OK,接着我们将其在实际项目中试试,babel的插件必须以
babel-plugin-*
开头,同时由于该插件是转化了代码,所以我们就将其命名为babel-plugin-transform-remove-debugger
:我们直接在
create-react-app
中看看效果:将我们的插件配置其中:
在点击按钮的时候可以看见,并没有出现断点,所以我们的插件是ok的,至此我们就完成了一个插件,是不是很简单??后面当我想把该插件发布的时候,发先npm上已经有一个了,这就勾起了我的好奇心,想知道实现上有何不同,果然实现思路都是一样,就多了一个命名与严格模式,哈哈。
关于babel,自己还会继续深入学习,看看其他著名的插件是如何实现的,并会做记录。
参考资料
Babel 用户手册
Babel 插件手册
从零开始编写一个babel插件
The text was updated successfully, but these errors were encountered: