利用AST解决项目webpack alias泛滥问题
栏目: JavaScript · 发布时间: 5年前
内容简介:那么代码怎样才能解析成这一棵 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生成以上所述就是小编给大家介绍的《利用AST解决项目webpack alias泛滥问题》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 黑客不过年:steam盗号木马再泛滥
- Mint木马变种泛滥,伪装“抖音电脑版”肆虐网络
- LWN:利用debounce buffer来阻止恶意设备利用DMA窃取信息
- 新医药 Leon Nanodrugs完成1850万欧元A轮融资,利用粒子合成方法提高药物利用率
- JNDI 注入利用工具
- Outlook滥用利用链
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。