前面的配置基本上是基于 spa,不过如果细心的同学可能会发现,之前在 5-5 webapck-dev-server 解决单页应用路由问题 一文中已经用到了多页面打包。其实,多页应用很简单,不过是指定多个入口,多个对应输出,以及将输出正确放到 html 中即可。
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const path = require('path');
module.exports = {
entry: {
index: './src/index.jsx',
list: './src/list.jsx',
},
output: {
path: path.resolve(__dirname, '../dist'),
filename: '[name].js',
},
resolve: {
extensions: ['.js', '.jsx'],
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node-modules/,
use: ['babel-loader'],
},
{
test: /\.(jpg|jpeg|png|gif)$/,
use: {
loader: 'url-loader',
options: {
name: '[name].[ext]',
limit: 2048,
},
},
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(eot|svg|ttf|woff)$/,
use: 'file-loader',
},
],
},
optimization: {
runtimeChunk: {
name: 'runtime',
},
splitChunks: {
chunks: 'all',
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
name: 'vendors',
},
},
},
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
}),
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'list.html',
}),
new CleanWebpackPlugin(),
],
};
<!--src/index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>esmodule-oop</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
// src/index.jsx
import React, { Component } from 'react';
import ReactDom from 'react-dom';
class App extends Component {
render() {
return <div>index page</div>;
}
}
ReactDom.render(<App />, document.getElementById('root'));
// src/index.jsx
import React, { Component } from 'react';
import ReactDom from 'react-dom';
class App extends Component {
render() {
return <div>index page</div>;
}
}
ReactDom.render(<App />, document.getElementById('root'));
bpm run dev 后,打开 index.html 和 list.html 都展示
image.png
这是因为 HtmlWebpackPlugin 默认引入所有的 chunks,如果不想引入所有 chunks,我们需要使用 chunks 和 excludeChunks 手动指定。
我们使用如下配置:
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
chunks: ['runtime', 'vendors', 'index'],
}),
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'list.html',
excludeChunks: ['index'],
}),
new CleanWebpackPlugin(),
],
打包后得出的结果就正常了。入口较多时,我们可以简化一下写法如下:
// build/webpack.common.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const path = require('path');
const entry = {
index: './src/index.jsx',
list: './src/list.jsx',
};
const plugins = [
new CleanWebpackPlugin(),
];
Object.keys(entry).forEach((name) => {
plugins.push(new HtmlWebpackPlugin({
template: './src/index.html',
filename: `${name}.html`,
chunks: ['runtime', 'vendors', name],
}));
});
module.exports = {
entry,
output: {
path: path.resolve(__dirname, '../dist'),
filename: '[name].js',
},
resolve: {
extensions: ['.js', '.jsx'],
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node-modules/,
use: ['babel-loader'],
},
{
test: /\.(jpg|jpeg|png|gif)$/,
use: {
loader: 'url-loader',
options: {
name: '[name].[ext]',
limit: 2048,
},
},
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(eot|svg|ttf|woff)$/,
use: 'file-loader',
},
],
},
optimization: {
runtimeChunk: {
name: 'runtime',
},
splitChunks: {
chunks: 'all',
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
name: 'vendors',
},
},
},
},
plugins,
};