基于babel实现vue文件扫描和节点替换(附demo)

244 阅读2分钟

业务代码中,如果有涉及对老代码进行改造,比如(新增国际化需求等),需要大量的人力成本,可以我们可以封装一个插件,实现对老代码的批量扫描和集中替换,可以大量节约成本,而且减少出错。

原理

比如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' })
}

总结

业务中如果有需要批量处理老代码的业务,可以基于一些工具来实现,从而实现对源代码的无痛修改,减少错误的产生,需要源代码的,可以评论区自取。