Webpack5 多页面应用(MPA)构建实践:统一目录与独立部署方案
作者:构建工坊时间:2026-10-31 21:23:43浏览:312
本文详解Webpack5多页面应用(MPA)的两种构建策略:统一目录部署与独立部署。通过glob动态生成入口与HtmlWebpackPlugin实例,配置externals排除外部依赖,并优化资源输出结构。对比两种模式在首屏加载、资源复用及部署灵活性上的差异,提供完整的配置代码与目录结构示例,帮助开发者实现高效的多页面打包。
| 特性维度 | 单页面应用-SPA | 多页面统一目录-MPA | 多页面单独部署-MPA |
|---|---|---|---|
| 入口数量 | 单个,只有一个 HTML 文件 | 多个,多个 HTML 文件 | 多个,多个 HTML 文件,分别打包输出 |
| 资源输出结构 | 所有资源输出到统一目录(如 js/, css/) | 所有页面的资源共用 js/, css/ 等目录 | 每页资源放在各自目录(如 index/js/, index/css/) |
| 公共资源复用 | 高:依赖打入主包或懒加载 chunk,资源完全共享 | 中:可通过 splitChunks 提取公共模块,多个页面共用依赖 | 低:默认每个页面依赖重复打包,需通过 CDN 或构建优化共享资源 |
| 首屏加载速度 | 中低:主包体积大需优化 | 高:每页只加载自身资源 | 高:每页打包独立、加载自身资源 |
| 项目推荐模式 | 用户交互复杂、状态集中、路由频繁 | 页面之间结构清晰、流程独立但资源共用 | 需要页面级灰度、子模块独立开发与部署 |
1. 示例多页面配置
- 主要涵盖外部依赖的排除、CDN资源的引入以及针对每个页面的CDN扩展配置。
- 利用工具自动扫描并生成对应的入口文件列表及HtmlWebpackPlugin实例。
- 最终导出包含入口配置、插件配置以及依赖过滤配置的完整对象,供主配置文件使用。
- entries:定义入口配置对象,直接用于webpack的entry字段。
- plugins:包含HtmlWebpackPlugin实例的数组,用于生成HTML文件。
- externals:供主配置引用的依赖过滤列表,用于排除特定模块的打包。
1.1多页面统一目录(MPA)
dist/
├── test1.html
├── test2.html
├── js/
│ ├── test1.[hash].js
│ └── test2.[hash].js
└── 图片、字体等资源const path = require("path");
const glob = require("glob");
const { merge } = require("webpack-merge");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const resolve = (dir) => path.resolve(__dirname, "..", dir);
// 打包排除某些依赖
const externals = {
vue: "Vue",
vuex: "Vuex",
"vue-router": "VueRouter",
axios: "axios",
vant: "vant",
};
// cdn资源
const assetsCDN = {
// 开发环境
dev: {
css: ["//xxx/npm/vant@2.12/lib/index.css"],
js: ["//xxx/npm/eruda@2.4/eruda.min.js"],
},
// 生产环境
build: {
css: ["//xxx/npm/vant@2.12/lib/index.css"],
js: [
"//xxx/npm/vue@2.6/dist/vue.min.js",
"//xxx/npm/vuex@3.6/dist/vuex.min.js",
"//xxx/npm/vue-router@3.5/dist/vue-router.min.js",
"//xxx/npm/axios@0.21/dist/axios.min.js",
"//xxx/npm/vant@2.12/lib/vant.min.js",
],
},
};
const entryCDN = {
test: {
dev: merge(assetsCDN.dev, {
css: [],
js: ["//res.wx.qq.com/open/js/jweixin-1.6.0.js"],
}),
build: merge(assetsCDN.build, {
css: [],
js: ["//res.wx.qq.com/open/js/jweixin-1.6.0.js"],
}),
},
};
const getEntry = () => {
// 多页面打包的入口集合
const entries = {};
// 多页面打包的模板集合
const plugins = [];
// 借助 glob 获取 src 目录下的所有入口文件
const globPath = resolve("src/views/**/main.js");
// 遍历文件集合,生成所需要的 entries、plugins 集合
glob.sync(globPath).map((item) => {
const match = item.match(/src/views/(.*)/main.js$/);
const name = match?.[1];
entries[name] = [item];
// CDN配置
const env = process.env.NODE_ENV === "production" ? "build" : "dev";
const pageCDN = (entryCDN[name] && entryCDN[name][env]) || assetsCDN[env];
if (!entryCDN[name]) {
console.warn(`页面 ${name} 未配置 entryCDN,已使用默认配置`);
}
// 多页面所需要的模板集合
plugins.push(
new HtmlWebpackPlugin({
title: "",
filename: `${name}.html`,
template: "public/index.html",
favicon: "public/favicon.ico",
chunks: [name],
minify:
process.env.NODE_ENV === "production"
? {
//压缩HTML文件
removeComments: true, // 移除HTML中的注释
collapseWhitespace: true, // 删除空白符和换行符
}
: false,
cdn: process.env.NODE_ENV === "production" ? entryCDN[name].build : entryCDN[name].dev,
})
);
});
// 对外输出页面打包需要的 入口集合、依赖过滤
return { entries, plugins, externals };
};
module.exports = getEntry();const { entries, plugins, externals } = require("./entry");
entry: {
base: ["core-js/stable", "regenerator-runtime/runtime"],
...entries
}1.2多页面单独部署(MPA)
dist/
├── test1/
│ ├── index.html
│ └── js/
│ └── test1.[hash].js
└── test2/
├── index.html
└── js/
└── test2.[hash].js// 在多页面统一目录的基础上新增配置
const CopyWebpackPlugin = require("copy-webpack-plugin");
const getEntry = () => {
// 多页面打包的入口集合
const entries = {};
// 多页面打包的模板集合
const plugins = [];
// 借助 glob 获取 src 目录下的所有入口文件
const globPath = resolve("src/views/**/main.js");
const base = ["core-js/stable", "regenerator-runtime/runtime"];
// 遍历文件集合,生成所需要的 entries、plugins 集合
glob.sync(globPath).map(item => {
const match = item.match(/src/views/(.*)/main.js$/);
const name = match?.[1];
entries[name] = [...base, item];
const env = process.env.NODE_ENV === "production" ? "build" : "dev";
const pageCDN = (entryCDN[name] && entryCDN[name][env]) || assetsCDN[env];
if (!entryCDN[name]) {
console.warn(`页面 ${name} 未配置 entryCDN,已使用默认配置`);
}
// 多页面所需要的模板集合
plugins.push(
new HtmlWebpackPlugin({
title: "",
filename: `${name}/index.html`,
template: "public/index.html",
// favicon: "public/favicon.ico",
chunks: [name],
minify:
process.env.NODE_ENV === "production"
? {
//压缩HTML文件
removeComments: true, // 移除HTML中的注释
collapseWhitespace: true // 删除空白符和换行符
}
: false,
cdn: pageCDN
}),
new CopyWebpackPlugin({
patterns: [{ from: "public/favicon.ico", to: `${name}/favicon.ico` }]
})
);
});
// 对外输出页面打包需要的 入口集合、依赖过滤
return { entries, plugins, externals };
};// 1. 注释掉 entry base 的配置
// 2. css、img、font的filename 增加 [name]/
splitChunks: false // ❌ 禁用公共拆包至此,关于Webpack5多页面项目实践的讲解结束。如需了解更多Webpack5多页面相关内容,建议查阅本站过往文章或继续浏览后续内容,感谢支持。
作者最新文章
JavaScript插件版本冲突怎么解决?npm安装报错排查
2026-11-03 23:58:39
怎么指定版本下载 pdf.js 旧版资源
2026-11-03 20:56:02
NW.js 应用打包指南:使用 nw-builder 生成多平台安装包
2026-11-03 20:07:02
JS控制台打印样式美化:使用%c自定义日志颜色
2026-11-02 10:29:52
Vue3 + Vite 项目创建与配置指南
2026-11-01 04:02:02
