可以根据不同的环境生成指定的路由文件,而不是一次性打包所有文件,默认可以遍历page目录下的所有.vue文件。
获取命令行参数
- 在package.json中新建一个scripts指令,带上参数,如
--test
- 新建
InitRouterPlugin.js
,使用yargs
模块获取命令行参数
const argv = require('yargs').argv
console.log(argv.test)
webpack钩子
生成路由文件应在所有事情开始之前执行,webpack提供的生命周期钩子实在太多,这里就挑了一个最靠前的afterPlugins
,有兴趣的可以看下这张完整的生命周期图。
webpack plugin的基本模板
webpack plugin对外暴露的apply
函数,通过apply函数获取主引擎compiler
module.exports = class InitRouterPlugin {
constructor(options) {
this.options = options
}
apply(compiler) {
compiler.hooks.afterPlugins.tap('InitRouterPlugin', async (context, entry) => {
await writeRouter()
})
}
}
写入路由
1、定义路由头部
这里奇怪的换行是为了生成后的文件保持格式规范
let route = `import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
const array = [
`
2、遍历page目录
这里使用的是路由懒加载模式
const fs = require('fs').promises
const path = require('path')
async function getPage(filePath) {
let files = await fs.readdir(filePath)
for (const filename of files) {
const filedir = path.join(filePath, filename)
const filehandle = await fs.open(filedir)
const stat = await filehandle.stat()
await filehandle.close()
const isFile = stat.isFile()
const isDir = stat.isDirectory()
if (isFile) {
route += ` { path: 'filename.split(".")[0]}', component: () => import('@/page${filedir.split("page")[1].replace(/\\/g, "/")}') },
`
}
if (isDir) {
await getPage(filedir) //递归,如果是文件夹,就继续遍历该文件夹下面的文件
}
}
}
fs模块的promise语法写起来舒服多了。
3、拼上结尾并写入文件
async function writeRouter() {
if (argv.test) {
// 自定义逻辑
} else {
await getPage(path.resolve('path/to/page'))
route = route.slice(0, -2) // 去掉最后一个换行和逗号
}
route += `
]
export default new Router({
routes: array
})
`
const routeFile = await fs.open(path.resolve('path/to/router.js'), 'w')
await routeFile.writeFile(route)
await routeFile.close()
}
总结
webpack内容实在太多,文档写的也不是很清楚,有些钩子的说明甚至只有一个名字,是让我们自己去摸索吗(╯°Д°)╯︵ ┻━┻,实在是太南了。目前新增vue文件的话需要重新编译才会生成新的路由文件。本来还想试试监听文件的改动实时更新router.js文件,但是没有找到合适的方法。如果只是文件内容的改动,而不是新增vue就触发的话,就过于频繁了,我认为没有必要。欢迎在评论区提出意见~