尽管单页面应用很流行,但是我们并不总是需要它。
在多页面应用程序中,server
会拉取一个新的 HTML
文档给你的客户端。页面重新加载此新文档,并且资源被重新下载。然而,这给了我们特殊的机会去做很多事,例如使用 optimization.splitChunks
为页面间共享的应用程序代码创建 bundle
。由于入口起点数量的增多,多页应用能够复用多个入口起点之间的大量代码/模块,从而可以极大地从这些技术中受益。
下面以一个例子来演示如何实现多页面应用程序
├── dist # 打包产物
├── public # 静态资源
│ │── index1.html # 应用① html模板
│ └── index2.html # 应用② html模板
├── src # 源码目录
│ ├── views # views 所有页面
│ └── main # 入口文件目录
│ ├── main1.js # 应用① 入口文件
│ └── main2.js # 应用② 入口文件
...
├── package.json # package.json
├── package-lock.json # package.json 锁定版本文件
└── webpack.config.js # webpack 配置文件
npm i webpack webpack-cli webpack-dev-server html-webpack-plugin -D
在之前 webpack基础篇(五):代码分离(Code Splitting)有过关于多入口(multi-main entry)的讲解,这里再来深入一下
main1.js
import _ from 'lodash'
console.log(_.join(['hello', 'app-1'], ' '));
main2.js
import _ from 'lodash'
console.log(_.join(['hello', 'app-2'], ' '));
webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development',
entry: { // 配置多入口
main1: {
import: './src/main/main1.js', // 启动时需加载的模块
dependOn: 'common_lodash', // 当前入口所依赖的入口
filename: 'app-1/[name].[contenthash].js', // 指定要输出的文件名称
},
main2: {
import: './src/main/main2.js',
dependOn: 'common_lodash',
filename: 'app-2/[name].[contenthash].js',
},
common_lodash: { // 这里是上面定义的公用依赖模块
import: 'lodash',
filename: 'common/[name].[contenthash].js',
},
},
output: {
clean: true
},
plugins: [
new HtmlWebpackPlugin(),
]
};
执行 webpack
,通过打包出来的文件大小可以看出,lodash
已经被打包到单独的js文件了
可以看到,会打包出来如下文件,
执行 npx webpack serve
可以看到能正常加载页面,并且控制台输出 hello app-1
、hello app-2
以上配置多入口实现了代码分离(普通js模块与公用模块)
用于描述入口的对象。你可以使用如下属性:
dependOn
: 当前入口所依赖的入口。它们必须在该入口被加载前被加载。filename
: 指定要输出的文件名称。import
: 启动时需加载的模块。library
: 指定 library 选项,为当前 entry 构建一个 library。runtime
: 运行时 chunk 的名字。如果设置了,就会创建一个新的运行时 chunk。在 webpack 5.43.0 之后可将其设为 false
以避免一个新的运行时 chunk。publicPath
: 当该入口的输出文件在浏览器中被引用时,为它们指定一个公共 URL 地址。请查看 output.publicPath。Tip
runtime
和dependOn
不能在同一个入口上同时使用- 确保
runtime
不能指向已存在的入口名称dependOn
不能循环引用
HtmlWebpackPlugin
简化了 HTML 文件的创建,以便为你的 webpack 包提供服务。这对于那些文件名中包含哈希值,并且哈希值会随着每次编译而改变的 webpack 包特别有用。你可以让该插件为你生成一个 HTML 文件,使用 lodash 模板提供模板,或者使用你自己的 loader。
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development',
entry: { // 配置多入口
main1: {
import: './src/main/main1.js', // 启动时需加载的模块
dependOn: 'common_lodash', // 当前入口所依赖的入口
filename: 'app-1/[name].[contenthash].js', // 指定要输出的文件名称
},
main2: {
import: './src/main/main2.js',
dependOn: 'common_lodash',
filename: 'app-2/[name].[contenthash].js',
},
common_lodash: { // 这里是上面定义的公用依赖模块
import: 'lodash',
filename: 'common/[name].[contenthash].js',
},
},
output: {
clean: true
},
plugins: [
new HtmlWebpackPlugin({
title: '多页面应用', // 用于生成的 HTML 文档的标题
template: './index.html', // 指定模板
filename: 'index.html', // 定义打包后输出的文件名
inject: 'body', // 将 script 放在 html 文件的什么位置
chunks: ['main1', 'common_lodash'] // 添加一些模块
})
]
};
根目录下新建 index.html
doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title><%= htmlWebpackPlugin.options.title %>title>
head>
<body>
body>
html>
执行 webpack
,查看 dist/index.html
,可以看到,我们刚刚的 HtmlWebpackPlugin
配置都生效了
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development',
entry: { // 配置多入口
main1: {
import: './src/main/main1.js', // 启动时需加载的模块
dependOn: 'common_lodash', // 当前入口所依赖的入口
filename: 'app-1/[name].[contenthash].js', // 指定要输出的文件名称
},
main2: {
import: './src/main/main2.js',
dependOn: 'common_lodash',
filename: 'app-2/[name].[contenthash].js',
},
common_lodash: { // 这里是上面定义的公用依赖模块
import: 'lodash',
filename: 'common/[name].[contenthash].js',
},
},
output: {
clean: true
},
devServer: {
static: path.resolve(__dirname, './dist')
},
plugins: [
new HtmlWebpackPlugin({
title: '应用1',
template: './public/index1.html',
filename: './app-1/index.html',
inject: 'body',
chunks: ['main1', 'common_lodash'],
}),
new HtmlWebpackPlugin({
title: '应用2',
template: './public/index2.html',
filename: './app-2/index.html',
inject: 'body',
chunks: ['main2', 'common_lodash'],
})
]
};
执行 webpack
可以看到,已经将两个应用
和common
都打包并且放入各自的目录中
执行npx webpack serve
可以看到界面加载正常,两个应用控制台分别会输出 hello app-1
、hello app-2
上面的
main1.js
main2.js
可以是我们实际项目中的main.js
入口文件
继续加油 ヾ(◍°∇°◍)ノ゙