概述
https://github.com/chalecao/parse_css_in_js
DSL 即「Domain Specific Language」,中文一般译为「领域特定语言」,在《领域特定语言》这本书中它有了一个定义:一种为特定领域设计的,具有受限表达性的编程语言。
DSL就是一种特定的语言,如 JSX
AST 即「Abstract syntax tree」,抽象语法树。
抽象语法树是将源代码根据其语法结构,省略一些细节(比如:括号没有生成节点),抽象成树形表达。
通过 https://astexplorer.net/ 这个在线工具,我们可以更直观的查看我们代码生成的AST。
应用:
- 高级语言的编译
- 编辑器高亮
- 前端应用:JavaScript 转译、CSS 预处理、代码压缩、ESLint、Prettier
原理
Babel 插件原理
解析->转换->代码生成
整个过程的原理也很简单,首先通过 babylon 这个词法语法分析器,生成 AST。将代码转换成按照特定语法组成的词汇 token 流集合,然后通过 traverse 遍历这个抽象语法树,通过对各个 token 处理,可以转换成需要的语法,比如将=>箭头函数转换成 function,将 let 转换成 var;最后通过 generator 生成符合规范的代码。
const fs = require("fs");
const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const { transformFromAst } = require("@babel/core");
module.exports = {
getAST: (path) => {
const content = fs.readFileSync(path, "utf-8");
return parser.parse(content, {
sourceType: "module",
});
},
getDependencis: (ast) => {
const dependencies = [];
traverse(ast, {
ImportDeclaration: ({ node }) => {
dependencies.push(node.source.value);
},
});
return dependencies;
},
transform: (ast) => {
const { code } = transformFromAst(ast, null, {
presets: ["@babel/preset-env"],
});
return code;
},
};
- @babel/parser: 转化为 AST 抽象语法树
- @babel/traverse:对AST进行递归遍历
- @babel/types:对具体的AST节点进行进行增、删、改、查;
- @babel/generator:将修改后的AST生成新的代码
@babel/parser(之前就是babylon)是从acorn fork 出来的
关于如何写babel插件可以参考这里:https://github.com/jamiebuilds/babel-handbook。
关于JSX 插件可以看这里:transform-react-jsx 插件的执行阶段是在 babel-traverse 阶段,通过访问者模式,可以访问到抽象语法树的各个节点,JSX 插件主要工作是找到 HTML 片段,将 HTML 转换成一个个具有层级嵌套关系的Virtual Node构成的virtual DOM,准确的说是一个vnode函数。这个函数的参数是元素类型,元素的属性和子元素。