背景
公司每年都有不同的H5活动(vue2)上线、下线,这些代码都在存在于同一个仓库中。
虽然过期的活动代码,增加了无效的编译时间和打包内容,但是我们并不想删除它们,毕竟代码即资产。
所以,我们希望实现一种方案,既能保留所有活动路由,又能将过期活动内容从包中剔除。
webpack loader
loader 用于对模块的源代码进行转换。我们可以编写一个 loader 来参与 webpack 打包过程,进而修改源代码。一个最简单的 loader 如下——它把接收到的源码原封不动的返回了:
module.exports = function doNothingLoader(content) {
return content
}
修剪路由AST
使用自定义 loader,我们就可以在 webpack 打包时修改源码而不会产生副作用。具体的思路是:通过this.resourcePath
识别源代码是否为路由文件,若是,则解析代码,并将其中的component
字段删除,以达到保留路由而删除内容的目的。
router.js源码
import router from "@/router";
const routes = [{
name: 'test',
path: '/promotion/test',
component: () => import(/* webpackChunkName: 'promotion/pages/test' */'./pages/test/index'),
meta: {
title: '测试'
}
}]
router.addRoutes(routes);
修剪后(删除了 component 字段)
import router from "@/router";
const routes = [{
name: 'test',
path: '/promotion/test',
meta: {
title: '测试'
}
}]
router.addRoutes(routes);
代码实现
通过 babel 插件,可以修改 babel 转换后的 AST 树。复制任何有效的JS代码到astexplorer,能够非常清晰的看到其AST结构。
我们要做的事就变得很简单了:如果是路由文件,则遍历其 AST,找到component
字段并删除。
const babel = require('babel-core'); // v6.26.0
const isWin = /^win/.test(process.platform)
const normalizePath = path => (isWin ? path.replace(/\\/g, '/') : path)
const routerRegx = /projects\/test\/(.*)router\.js/
const isInvalidRoute = () => null // 根据项目实际情况实现 isInvalidRoute
const pruneInvalidRoute = {
visitor: {
ObjectExpression(path) {
const pathNode = (path.node.properties || []).find(p => p.key.name === 'path')
if (pathNode) {
const routeVal = pathNode.value.value || ''
if (isInvalidRoute(routeVal) {
const compIndex = properties.findIndex(p => p.key.name === 'component')
if (compIndex >= 0) {
properties.splice(compIndex, 1)
return
}
}
}
}
}
}
module.exports = function pruneInvalidRouteLoader(content) {
const filePath = normalizePath(this.resourcePath)
const matched = routerRegx.test(filePath)
if (!matched) return content
const result = babel.transformFileSync(filePath, {plugins: [pruneInvalidRoute]})
return result.code
}
唯一要注意的是,由于 babel 的版本差异,其接口略有不同,具体可查看版本对应文档。本文所用的babel-core
版本为:6.26.0。