书接上文(如何将vue2源码一键升级到vue3(上)),我们知道了如何通过ast去改造源码,本篇文章将介绍如何通过vue自定义loader的方式实现vue2的代码运行在基于vue3的项目当中。源码地址 vue2-to-vue3。
关于loader
可以将其理解为在文件打包构建完成之前,对文件进行预处理,譬如我们熟知less-loader、sass-loader的作用就是将其转换为css输出,编写自定义loader的目的也是将文件按照我们的预期输出,更多关于loader的内容大家可以在Loaders上查阅。
目标
- 入口文件main.js改造
- vue文件改造
- 项目vue版本升级为3.x 以及相关依赖版本替换
- 跑起来
准备工作
新建一个vue2项目,在src目录下新建loader文件夹,其中包含index.js入口文件以及custom-loader文件,项目结构如下:
在vue.config.js对我们的自定义loader进行配置
// vue.config.js
const {
defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
chainWebpack: config => {
// 配置自定义loader
config.module
.rule('custom-loader')
// 匹配.vue和js文件
.test(/\.(vue|js)$/)
.include.add(/src/) // 只转化src目录下的js
.end()
.use('custom-loader')
.loader(require.resolve('./src/loader'))
.end()
}
})
编写loader/index.js文件,source为源文件内容,在loader导出的函数中, this
作为上下文会被 webpack 填充,所以此处不能使用箭头函数,最后函数通过webpack注入到this上的callback()返回最终结果。
// src/loader/index.js
const loader = require('./custom-loader');
const compiler = function(source) {
// 实例化loader,传入源代码,调用transform方法获取转换后的代码
let result = new loader(source).transform();
// console.log('result :>> ', result);
return result;
};
module.exports = function (source) {
this.callback(null,compiler(source),null);
};
编写loader/custom-loader.js,改造相关的逻辑都会在该文件下进行。
// src/loader/custom-loader.js
const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");
const generator = require("@babel/generator").default;
/**
* 转换类
* @param {string} source 源代码
* @returns {string} 转换后的代码
*/
class Transformer {
constructor(source) {
this.source = source;
}
// 转换
transform() {
return compileCode(this.source);
}
}
module.exports = Transformer;
function compileCode(source) {
// 1. 生成AST
const ast = parser.parse(source, {
sourceType: 'module'
});
// 2. 遍历AST,找到对应的节点
traverse(ast, {
// 遍历 函数调用表达式 类型的节点
CallExpression(path) {
// 判断是否是console.log节点
if (t.isMemberExpression