业务代码中,如果有涉及对老代码进行改造,比如(新增国际化需求等),需要大量的人力成本,可以我们可以封装一个插件,实现对老代码的批量扫描和集中替换,可以大量节约成本,而且减少出错。
原理
比如vue文件来说,因为vue是单文件类型(一个文件中包含模版,js,样式),我们需要解析出对应的js,template,style,逐一进行解析,制定解析规则,最后重组,生成新的code来替换,从而无缝实现对老代码的批量修改和替换.
实现
1. 实现scan命令
基于node的commander来实现命令的实现
const { Command } = require('commander');
const collect = require('./command/collect');
const program = new Command();
program
.command('scan')
.alias('s')
.description('scan your file')
.action(function() {
collect(program.opts())
})
program.parse();
2. vue-template-compiler解析vue
指定解析的入口文件(entry),制定解析规则(只解析src目录下的js, vue文件), 通过vue-template-compiler解析vue文件,得到template, script等;然后对template和script单独解析和替换
function transformVue(sourceCode) {
const sfc = compiler.parseComponent(sourceCode, {
pad: 'space',
deindent: false
})
const { template, script, styles, customBlocks } = sfc;
const templateRet = transforHTML(template.content)
template.content = templateRet.source;
const scriptRet = transforJS(script.content);
script.content = scriptRet.source;
const code = combineVue(template, script, styles, customBlocks);
return {
source: code
}
}
3. template解析替换
对于模版语法类型属于pug的,我们通过pug-lexer解析成词法单元,在通过pug-parser解析成ast, 然后对ast进行转换和替换
module.exports = function transformPug(source, localeInfo = {}, options = {}) {
const tokens = lex(source.trim());
const ast = parse(tokens);
traversePug(ast, opts, r);
let code = source;
return { source: code };
};
根据节点属性进行逐一替换和更新
4. js解析替换
对于script语法,利用babel解析成ast,然后定义好visitor(对不同节点,采用不同处理方式),通过递归ast,转换不同的节点,最后利用babel/generator生产转换后的code;
module.exports = function transformJs(source, localeInfo = {}, options = {}) {
const ast = babel.parseSync(source, transformOptions);
opts.ignoreLines = getIgnoreLines(ast);
const visitor = makeVisitor(opts, r);
traverse(ast, visitor);
let { code } = generate(ast, { retainLines: true, decoratorsBeforeExport: true }, source);
return { source: code };
};
visitor是定义对不同节点的解析规则
5. 组合&重写源文件
转换完以后重组vue文件,然后进行文件重写,就可以实现对源代码的批量修改;
function transformCode(codeFile) {
const { filePath } = codeFile;
const sourceCode = fs.readFileSync(filePath, 'utf8');
const { source } = transformVue(sourceCode);
fs.writeFileSync(filePath, source, { encoding: 'utf-8' })
}
总结
业务中如果有需要批量处理老代码的业务,可以基于一些工具来实现,从而实现对源代码的无痛修改,减少错误的产生,需要源代码的,可以评论区自取。