二、多入口
在单页应用中,我们的入口文件只有一个, CLI 默认配置的是 main.js ,但是到了多页应用,我们的入口文件便包含了 page1.js 、 page2.js 、 index.js 等,数量取决于 pages 文件夹下目录的个数,这时候为了项目的可拓展性,我们需要自动计算入口文件的数量并解析路径配置到 webpack 中的 entry 属性上,如:
module.exports = { ... entry: { page1: '/xxx/pages/page1/page1.js', page2: '/xxx/pages/page2/page2.js', index: '/xxx/pages/index/index.js', }, ... }
那么我们如何读取并解析这样的路径呢,这里就需要使用工具和函数来解决了。我们可以在根目录新建 build 文件夹存放 utils.js 这样共用的 webpack 功能性文件,并加入多入口读取解析方法
/* utils.js */ const path = require('path'); // glob 是 webpack 安装时依赖的一个第三方模块,该模块允许你使用 * 等符号, // 例如 lib/*.js 就是获取 lib 文件夹下的所有 js 后缀名的文件 const glob = require('glob'); // 取得相应的页面路径,因为之前的配置,所以是 src 文件夹下的 pages 文件夹 const PAGE_PATH = path.resolve(__dirname, '../src/pages'); /* * 多入口配置 * 通过 glob 模块读取 pages 文件夹下的所有对应文件夹下的 js * 后缀文件,如果该文件存在 * 那么就作为入口处理 */ exports.getEntries = () => { let entryFiles = glob.sync(PAGE_PATH + '/*/*.js') // 同步读取所有入口文件 let map = {} // 遍历所有入口文件 entryFiles.forEach(filePath => { // 获取文件名 let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.')) // 以键值对的形式存储 map[filename] = filePath }) return map }
读取并存储完毕后,我们得到了一个入口文件的对象集合,这个对象我们便可以将其设置到 webpack 的 entry 属性上,这里我们需要修改 vue.config.js 的配置来间接修改 webpack 的值
/* vue.config.js */ const utils = require('./build/utils') module.exports = { ... configureWebpack: config => { config.entry = utils.getEntries() }, ... }
这样我们多入口的设置便完成了,当然这并不是 CLI 所希望的操作,后面我们会进行改进。
三、多模板
相对于多入口来说,多模板的配置也是大同小异,这里所说的模板便是每个 page 下的 html 模板文件,而模板文件的作用主要用于 webpack 中 html-webpack-plugin 插件的配置,其会根据模板文件生产一个编译后的 html 文件并自动加入携带 hash 的脚本和样式,基本配置如下
/* webpack 配置文件 */ const HtmlWebpackPlugin = require('html-webpack-plugin') // 安装并引用插件 module.exports = { ... plugins: [ new HtmlWebpackPlugin({ title: 'My Page', // 生成 html 中的 title filename: 'demo.html', // 生成 html 的文件名 template: 'xxx/xxx/demo.html', // 模板路径 chunks: ['manifest', 'vendor', 'demo'], // 所要包含的模块 inject: true, // 是否注入资源 }) ] ... }
以上是单模板的配置,那么如果是多模板只要继续往 plugins 数组中添加 HtmlWebpackPlugin 即可,但是为了和多入口一样能够灵活的获取 pages 目录下所有模板文件并进行配置,我们可以在 utils.js 中添加多模板的读取解析方法
/* utils.js */ // 多页面
/* vue.config.js */ const utils = require('./build/utils') module.exports = { ... configureWebpack: config => { config.entry = utils.getEntries() // 直接覆盖 entry 配置 // 使用 return 一个对象会通过 webpack-merge 进行合并,plugins 不会置空 return { plugins: [...utils.htmlPlugin()] } }, ... }
如此我们多页应用的多入口和多模板的配置就完成了,这时候我们运行命令 yarn build 后你会发现 dist 目录下生成了 3 个 html 文件,分别是 index.html 、 page1.html 和 page2.html
四、使用 pages 配置
其实,在 vue.config.js 中,我们还有一个配置没有使用,便是 pages 。 pages 对象允许我们为应用配置多个入口及模板,这就为我们的多页应用提供了开放的配置入口。官方示例代码如下
/* vue.config.js */ module.exports = { pages: { index: { // page 的入口 entry: 'src/index/main.js', // 模板来源 template: 'public/index.html', // 在 dist/index.html 的
我们不难发现, pages 对象中的 key 就是入口的别名,而其 value 对象其实是入口 entry 和模板属性的合并,这样我们上述介绍的获取多入口和多模板的方法就可以合并成一个函数来进行多页的处理,合并后的 setPages 方法如下
// pages 多入口配置 exports.setPages = configs => { let entryFiles = glob.sync(PAGE_PATH + '/*/*.js') let map = {} entryFiles.forEach(filePath => { let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.')) let tmp = filePath.substring(0, filePath.lastIndexOf('\/')) let conf = { // page 的入口 entry: filePath, // 模板来源 template: tmp + '.html', // 在 dist/index.html 的
上述代码我们 return 出的 map 对象就是 pages 所需要的配置项结构,我们只需在 vue.config.js 中引用即可
/* vue.config.js */ const utils = require('./build/utils') module.exports = { ... pages: utils.setPages(), ... }
这样我们多页应用基于 pages 配置的改进就大功告成了,当你运行打包命令来查看输出结果的时候,你会发现和之前的方式相比并没有什么变化,这就说明这两种方式都适用于多页的构建,但是这里还是推荐大家使用更便捷的 pages 配置
总结