# cli3-page **Repository Path**: liu942/cli3-page ## Basic Information - **Project Name**: cli3-page - **Description**: 根据pages目录生成多页面接口 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2019-03-04 - **Last Updated**: 2020-12-20 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 初始化项目 首先我们安装好vue-cli3脚手架,并初始化一个默认项目: ``` $ npm i -g @vue-cli $ vue create pageuser ``` ## 特性 - ✅ 自动生成入口,所有入口以目录的形式存放于src/pages下,并在第一层目录需包含index.html文件 - ✅ 支持嵌套路由,如在pages目录下存在/test/page1/index.html,访问路径为:/test/page1 - ✅ 根目录挂载,目录名为index会挂载到根目录下,而不是通过/index访问 1. 通过一个pages目录来存放不同的入口,每个入口包含:index.html、main.js,pages,其中文件夹名即路由名 2. src目录下可以存放项目的通用组件和静态资源,每个入口单独管理自己独有的资源 通过以上考虑,决定将工程结果重构为: ``` ... ├── public │   └── favicon.ico ├── src │   ├── assets │   ├── components │   └── pages │   └── page1 │   ├── App.vue │   ├── assets │   │   └── logo.png │   ├── components │   │   └── HelloWorld.vue │   ├── index.html │   └── main.js │   └── page2 │   ├── ... ``` ## Multi-Page模式 Vue CLI 3 支持多入口模式,只需要在vue.config.js中提供pages选项即可开启[多入口模式](https://cli.vuejs.org/zh/config/#pages),我们现在将使用pages字段来重构vue.config.js: ``` module.exports = { pages: { index: { // page 的入口 entry: "src/pages/page1/main.js", // 模板来源 template: "src/pages/page1/index.html", // 在 dist/index.html 的输出 filename: "index.html", // 当使用 title 选项时, // template 中的 title 标签需要是 <%= htmlWebpackPlugin.options.title %> title: "Index Page", // 在这个页面中包含的块,默认情况下会包含 // 提取出来的通用 chunk 和 vendor chunk。 chunks: ["chunk-vendors", "chunk-common", "index"] } } }; ``` 配置完成后,服务依然正确访问,至此已经完成了添加多入口的基本准备工作,借助于脚手架多入口构建模式,因此需要做的工作仅剩下一个:**通过目录结构生成对应的入口配置**,也就是说,我们需要实现一个函数,函数的具体功能为: ![](http://7xp5r4.com1.z0.glb.clouddn.com/18-8-14/41944374.jpg) 以下是具体配置: ``` // vue.config.js const path = require('path'); const fs = require('fs'); const config = { entry: 'main.js', html: 'index.html', pagesRoot: path.resolve(__dirname, 'src/pages') }; const genRoutes = () => { const allRoutes = []; const findAllRoutes = (source, routes) => { const files = fs.readdirSync(source); files.forEach(filename => { const fullname = path.join(source, filename); const stats = fs.statSync(fullname); if (!stats.isDirectory()) return; if (fs.existsSync(`${fullname}/${config.html}`)) { routes.push(fullname); } else { findAllRoutes(fullname, routes); } }); }; findAllRoutes(config.pagesRoot, allRoutes); return allRoutes; }; const genPages = () => { const pages = {}; genRoutes().forEach(route => { const filename = route.slice(config.pagesRoot.length + 1); pages[filename] = { entry: `${route}/${config.entry}`, template: `${route}/${config.html}`, filename: filename === 'index' ? config.html : `${filename}/${config.html}` }; }); return pages; }; const pages = genPages(); module.exports = { pages, productionSourceMap: false, }; ``` 通过以上配置后,如果是page1的入口,则会最终在dist目录生成一个:`page1/index.html`,因此还需要设置vue.config.js中的devServer.historyApiFallback,确保任意的 404 响应都可能需要被替代为 index.html正常返回: ``` ... devServer: { historyApiFallback: true, }, ... ``` #### 移除prefetch 由于本人并不喜欢为将来做打算,因此并不希望预加载一些可能会用到的asyncChunk,因为会浪费掉一些带宽,而且在多页面中并不见得预加载其他入口的文件是一件好事情,于是我们通过chainWebpack进行删除: ``` modules.exports = { // ... chainWebpack: config => { Object.keys(pages).forEach(entryName => { config.plugins.delete(`prefetch-${entryName}`); }); } } ``` #### 关闭SourceMap 关闭之后不仅能加快生产环境的打包速度,也能避免源码暴露在浏览器端: ``` modules.exports = { // ... productionSourceMap: false, } ``` #### 打包分类(强迫症患者福音) 首先回顾一下dist中的部分文件夹: ``` . ├── css │   ├── page1.5f9ed80b.css │   └── page2.80dc2e75.css ├── js │   ├── chunk-vendors.f061f10e.js │   ├── chunk-vendors.f061f10e.js.map │   ├── page1.973fb73f.js │   ├── page1.973fb73f.js.map │   ├── page2.5e495ede.js │   └── page2.5e495ede.js.map ├── page1 │   └── index.html └── page2 └── index.html ``` 其实我们更希望的是不同入口的css与js文件放入不同入口中,而不是统一放在一个js和css文件夹,为了做到这一点,js打包路径我们可已通过修改webpack的output配置来完成,而css打包路径,脚手架是通过MiniCssExtractPlugin插件来完成的,因此可以使用chainWebpack的tap来修改其配置,以上只需要在生产环境修改即可: ``` modules.exports = { // ... chainWebpack: config => { // ... if (process.env.NODE_ENV === "production") { config.plugin("extract-css").tap(() => (() => [ { filename: "[name]/css/[name].[contenthash:8].css", chunkFilename: "[name]/css/[name].[contenthash:8].css" } ])); } }, configureWebpack: config => { if (process.env.NODE_ENV === "production") { config.output = { path: path.join(__dirname, "./dist"), filename: "[name]/js/[name].[contenthash:8].js", publicPath: "/", chunkFilename: "[name]/js/[name].[contenthash:8].js" }; } } } ``` 此时打包后的dist文件夹为: ``` ├── page1 │   ├── css │   │   └── page1.42195c95.css │   ├── index.html │   └── js │   └── page1.569bf4e5.js └── page2 ├── css │   └── page2.4e7ad924.css ├── index.html └── js └── page2.05e51252.js ```