# 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"]
}
}
};
```
配置完成后,服务依然正确访问,至此已经完成了添加多入口的基本准备工作,借助于脚手架多入口构建模式,因此需要做的工作仅剩下一个:**通过目录结构生成对应的入口配置**,也就是说,我们需要实现一个函数,函数的具体功能为:

以下是具体配置:
```
// 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
```