利用AST解决项目webpack alias泛滥问题
栏目: JavaScript · 发布时间: 7年前
内容简介:那么代码怎样才能解析成这一棵 AST, AST在前端领域一般又可以干嘛?ast是由编译器解析生成的,简单的编译器可以由以下几部分组成:我们前端构建中很常用的babel就是这种原理
AST(Abstract Syntax Tree)既抽象语法树,或称语法树,简单来说就是代码语法结构的一种抽象表示。比如 var answer = 6 * 7; 会被解析为这么一棵树
那么代码怎样才能解析成这一棵 AST, AST在前端领域一般又可以干嘛?
编译器
ast是由编译器解析生成的,简单的编译器可以由以下几部分组成:
tokens
我们前端构建中很常用的babel就是这种原理
babel 初始阶段并没有做任何事,基本上等于 const babel = code=> code; 先 tokenizer, parser 解析代码,再 transformer 的时候,完全不改动原来的 ast
对编译器原理有兴趣的,可以看我以前写的小demo,500行简单易懂 min-compiler ,看完会有个整体概念。
而生成的AST我们可以用来做什么?
AST你都拿到了,剩下的事情就是对这棵树做你想要的操作,比如代码转换(babel),代码压缩等。
这里我用他来处理webpack的alias泛滥问题。
webpack alias问题
webpack alias 在很多情况下可以提供便利,但是如果项目参加的人太多,又没有什么约束,大家贪图方便什么都加到alias….就会变成这样子
- 很多你不知道他到底是node_modules里面的包还是自己封装过的
- 很多写二级路径就可以获取到的,没必要多加个alias
- 现在比较推崇不是很远的路径都写成相对路径,编辑器可以直接跳过去方便(虽然这个可以通过jsconfig来解决,但是太多看着也很烦)
所以我决定把项目里的alias从23个缩减为7个。
利用 estools 解决webpack Alias
我们先来整理一下思路
- 先用解析器把代码解析成 AST
- 再找出我们需要去除的alias,把他改为其他值,生成新的AST
- 把新的AST转为代码,重新写入文件
我们这里的把alias改为其他值,指的是这种情况
目录结构:
- src
- components
- btn
alias: {
btn: path.resolve(basepath, 'src/components/btn'),
btn: path.resolve(basepath, 'src/components'),
}
原来的引入 import Btn from 'btn';
改为 import Btn from 'components/btn';
这里我们用 esprima 来做代码分析生成ast,用 estraverse 来转换代码,用 escodegen 生成代码。直接上代码
const aliasConfig = { /* webpack alias 配置*/}
function translateAlias(filePath) {
// 解析ast
const codeStr = fs.readFileSync(filePath).toString();
const ast = esprima.parseModule(codeStr);
// 转换ast
estraverse.traverse(ast, {
// 对于每个node节点都会进入这个函数
enter(node, parent) {
// 判断是否是我们的目标文件
const isAliasDec = isRequireDeclaration(node, parent);
if (isAliasDec) {
// 替换掉alias => newAlias
const newVal = getModulePath(node.value, filePath);
node.value = newVal;
}
},
});
// 重新生成代码
const newCodeStr = escodegen.generate(ast);
fs.writeFileSync(filePath, newCodeStr, {});
}
// 工具函数: 判断是否是 require
function isRequireDeclaration(node, parent) {
const { type, value } = node;
const { callee } = parent || {};
// 类型一致 && 该key在aliasKey中 && 是 require引入的
return (
type === 'Literal' &&
aliasKey.includes(value) &&
!allowAliasKey.includes(value) &&
isRequest(callee)
);
}
// 工具函数:获取路径
function getModulePath(aliasKey, filePath) {
const firstDir = /\w*/.exec(aliasKey)[0];
const modulePath = aliasKey.replace(firstDir, aliasConfig[firstDir]);
const aliasPath = aliasKey.replace(firstDir, aliasMap[firstDir]);
if (!aliasConfig[firstDir] || !aliasMap[firstDir] || allowAliasKey.includes(firstDir)) return false;
// 获取引入的模块与当前模块相对路径,判断是否太长,是就返回alias,否则就返回相对路径就完事了
const relativePath = path.relative(filePath, modulePath);
const relativeTime = relativePath.split('../').length - 1;
return (relativeTime < MAX_RELATIVE)? relativePath: aliasPath;
}
translateAlias(filePath);
试跑了一下,发现说虽然代码引用确实有被替换了,但是代码里面的所有空行和注释都丢了,而且一些规范格式也和原来不一样。
这显然是不行的,先不说格式的问题,一个文件连换行和注释都没有,那他就是没有灵魂的js~
看了下这是因为 esprima 在解析的时候,遇到空行和注释会直接跳过不解析生成AST,所以会导致后面生成的代码没有空行和注释。
babel解决空行和注释等问题、prettier保持代码风格一致
我们平时项目上用的最多的转换代码的 工具 就是babel,那么我们也可以把 esTool 那一套换成 babel 生态,用babel来帮我们做这些转换。
原理和思路基本上是一样的,用 babylon 解析, babel-traverse 转换,再用 babel-generator 生成代码。
生成之后,先不写进去,而是用 prettier 格式化一遍再重写到本地,以保持和原来的风格一致。
function translateAlias(filePath) {
console.log(`开始处理第${i++}个: ${filePath}`)
const code = fs.readFileSync(filePath).toString();
// 获取ast
const ast = babylon.parse(code, {
sourceType: 'module',
plugins: ['jsx', 'objectRestSpread']
});
traverse(ast, {
enter(path) {
// 转换 CommonJs 的情况
translateRequireModulePath(path, filePath);
// 转换 ESM 的情况
translateImportModulePath(path, filePath);
}
});
const newCode = generate(ast, {});
// 重新用项目的prettier配置格式化多一次再写入
const prettierCode = prettier.format(newCode.code, prettierConfig);
fs.writeFileSync(filePath, prettierCode);
console.log(`处理结束${filePath}`)
}
到此减少webpack-alias的功能处理完成,最后总结一下
- 用
glob读取所有要转的js文件 - 用
babylon将js文件解析成AST - 用
babel-traverse处理AST,判断如果是require('xxx')或者import xxx from 'xxx'替换掉这些路径 - 用
babel-generator将新生成的AST转化为代码 - 用
prettier格式化新生成的代码,保持与原项目风格一致 - 重新写入本地文件
告辞!
以上所述就是小编给大家介绍的《利用AST解决项目webpack alias泛滥问题》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Beginning XML with DOM and Ajax
Sas Jacobs / Apress / 2006-06-05 / USD 39.99
Don't waste time on 1,000-page tomes full of syntax; this book is all you need to get ahead in XML development. Renowned web developer Sas Jacobs presents an essential guide to XML. Beginning XML with......一起来看看 《Beginning XML with DOM and Ajax》 这本书的介绍吧!