一个自动生成vue路由文件的webpack插件

2,154 阅读2分钟

可以根据不同的环境生成指定的路由文件,而不是一次性打包所有文件,默认可以遍历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就触发的话,就过于频繁了,我认为没有必要。欢迎在评论区提出意见~