我的回答
entry中增加多个html入口, 在html-webpack-plugin中设置对应的多个html模板和配置
参考回答
Vue-cli 多页面配置
单页应用(SPA)往往只含有一个主入口文件与index.html,页面间切换通过局部刷新资源来完成。而在多页应用中,我们会为每个html文档文件都指定好一个JS入口,这样一来当页面跳转时用户会获得一个新的html文档,整个页面会重新加载。
vue-cli可以配置vue.config.js的pages选项,实现多页面应用开发
module.exports = {
pages: {
index: {
// page 的入口(必选项,除此之外就是可选项)
entry: "src/index/main.js",
// 模板来源
template: "public/index.html",
// 在 dist/index.html 的输出
filename: "index.html",
// 当使用 title 选项时,
// template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
title: "Index Page",
// 在这个页面中包含的块,默认情况下会包含
// 提取出来的通用 chunk 和 vendor chunk。
chunks: ["chunk-vendors", "chunk-common", "index"],
},
// 当使用只有入口的字符串格式时,
// 模板会被推导为 `public/subpage.html`
// 并且如果找不到的话,就回退到 `public/index.html`。
// 输出文件名会被推导为 `subpage.html`。
subpage: "src/subpage/main.js",
},
};
1.1 初始化项目
通过vue-cli脚手架初始化一个默认工程,修改项目目录
├── assets
│ └── logo.png
├── components
│ ├── About.vue
│ ├── HelloWorld.vue
│ └── Home.vue
├── pages
│ ├── page1
│ │ ├── page1.html
│ │ ├── page1.js
│ │ └── page1.vue
│ └── page2
│ ├── page2.html
│ ├── page2.js
│ └── page2.vue
└── style
├── common.css
└── common.less
vue.config.js是一个可选文件,用户需要自行创建,他会被@vue/cli-service读取。当正确添加配置后,重启一下项目,测试一下项目在改变目录结构后是否正常运行。
1.2 vue.config.js配置
let path = require("path");
let glob = require("glob");
//配置pages多页面获取当前文件夹下的html和js
function getEntry(globPath) {
let entries = {},
basename,
tmp,
pathname,
appname;
glob.sync(globPath).forEach(function (entry) {
basename = path.basename(entry, path.extname(entry));
// console.log(entry)
tmp = entry.split("/").splice(-3);
console.log(tmp);
pathname = basename; // 正确输出js和html的路径
// console.log(pathname)
entries[pathname] = {
entry: "src/" + tmp[0] + "/" + tmp[1] + "/" + tmp[1] + ".js",
template: "src/" + tmp[0] + "/" + tmp[1] + "/" + tmp[2],
title: tmp[2],
filename: tmp[2],
};
});
return entries;
}
let pages = getEntry("./src/pages/**?/*.html");
console.log(pages);
//配置end
module.exports = {
pages,
};
1.3 dist打包目录
├── css
│ ├── page1.9951d5a1.css
│ └── page2.009d0d6f.css
├── img
│ └── logo.82b9c7a5.png
├── js
│ ├── chunk-vendors.f061f10e.js
│ ├── page1.5a5322e0.js
│ └── page2.db57562b.js
├── page1.html
└── page2.html
1.4 源码部分
@vue/cli-service通过判断是否传入pages参数来生成对应 webpack 配置文件
如果配置了pages选项,则会执行下面步骤:
- 清除原有entry 对pages字段的每个key做循环
- 解析每个入口对象的参数entry(必选)、title、template、filename、chunks
通过entry字段生成 webpack 的entry入口
const multiPageConfig = options.pages
if (!multiPageConfig) {
// default, single page setup.
htmlOptions.template = fs.existsSync(htmlPath)
? htmlPath
: defaultHtmlPath
webpackConfig
.plugin('html')
.use(HTMLPlugin, [htmlOptions])
if (!isLegacyBundle) {
// inject preload/prefetch to HTML
...
}
}else{
// multi-page setup
webpackConfig.entryPoints.clear()
const pages = Object.keys(multiPageConfig)
const normalizePageConfig = c => typeof c === 'string' ? { entry: c } : c
pages.forEach(name => {
const pageConfig = normalizePageConfig(multiPageConfig[name])
const {
entry,
template = `public/${name}.html`,
filename = `${name}.html`,
chunks = ['chunk-vendors', 'chunk-common', name]
} = pageConfig
const customHtmlOptions = {}
for (const key in pageConfig) {
if (
!['entry', 'template', 'filename', 'chunks'].includes(key)
) {
customHtmlOptions[key] = pageConfig[key]
}
}
// inject entry
const entries = Array.isArray(entry) ? entry : [entry]
webpackConfig.entry(name).merge(entries.map(e => api.resolve(e)))
// resolve page index template
const hasDedicatedTemplate = fs.existsSync(api.resolve(template))
const templatePath = hasDedicatedTemplate
? template
: fs.existsSync(htmlPath)
? htmlPath
: defaultHtmlPath
publicCopyIgnore.push(api.resolve(templatePath).replace(/\\/g, '/'))
// inject html plugin for the page
const pageHtmlOptions = Object.assign(
{},
htmlOptions,
{
chunks,
template: templatePath,
filename: ensureRelative(outputDir, filename)
},
customHtmlOptions
)
webpackConfig
.plugin(`html-${name}`)
.use(HTMLPlugin, [pageHtmlOptions])
})
}