之前的配置是单页面应用,就是只有一个html文件。多页面应用就是多个html文件。实现多页面webpack配置基本思路就是采用多个入口配置,然后配置多个html-webpack-plugin来生成多个html文件。我们在之前的项目中新增一个登陆页面和退出页面(这里只是为了演示,大家根据实际实际情况自己配置)

1.文件结构

myProject
|-build
   |-base
       |-path.js
       |-config.js
+      |-html.js       
   |-mode.js
   |-entry.js
   |-devtool.js
   |-module.js
   |-plugins.js
   |-devServer.js
   |-optimization.js
   |-output.js
   |-resolve.js
 |-dist
 |-node_modules
 |-src
+   |-page
+       |-login
+            |-login.html
+            |-login.js
+       |-logout
+            |-logout.html
+            |-logout.js
    |-api
        |-apiPath.js
    |-util
        |-math.js
    |-assets
        |-css
            |-index.css
        |-less
            |-index.less     
        |-sass
            |-index.scss
        |-images
            |-wali_logo.png
    |-index.html
    |-index.js
+   |-favicon.ico  
 |-package.json
 |-webpack.config.js
 |-webpack.dll.js
 |-postcss.config.js
 |-.babelrc
 |-.eslintignore
 |-.eslintrc.js
 |-package-lock.json
 |-stats.json

2.webpack配置

src/page/login/login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>这是一个登陆页面</h1>
</body>
</html>

src/page/login/login.js

console.log('这是一个登陆页面');

src/page/logout/logout.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>这是一个退出页面</h1>
</body>
</html>

src/page/logout/logout.js

console.log('这是一个退出页面');

build/base/html.js

const dirPath = require('./path');
const path = require('path');
const fs = require('fs');
const HtmlWebpackPlugin = require('html-webpack-plugin');    //生成html文件

const getFiles = dir =>{   //遍历page下文件
    let results = [];
    let list = fs.readdirSync(dir);
    list.forEach(file=>{
        file = dir + '/' + file;
        let stat = fs.statSync(file);
        if(stat && stat.isDirectory()) results = results.concat(getFiles(file));
        else results.push(file);
    })
    return results;
}

let entry = {
    main: dirPath.src + '/index.js'
};
let plugins = [];
let files = getFiles(path.resolve(dirPath.src,'page'));

files.forEach(val=>{
    let name = val.replace(/(.*\/)*([^.]+).*/ig,"$2");
    if(/\.js$/.test(val)){            
        entry[name] = val;
    }
    if(/\.html$/.test(val)){
        let output = val.replace(/(.*\\)(.*\/)*([^.]+).*/ig,"$2");
        let file = val.replace(/(.*\/)*(.+).*/ig,"$2");
        let htmlConfig = {
			favicon: dirPath.src+'/favicon.ico',
			filename: output + file,   //热替换时如果有[hash]则会找不到页面
			template: val,
			inject:'body',		
			chunks:[`runtimechunk~${name}`,'vendors',name],    //只允许加载当前的chunk
			chunksSortMode:'auto',  //加载chunk的顺序
			excludeChunks:[], //排除某个 chunk
        }
        plugins.push(new HtmlWebpackPlugin(htmlConfig));
    }
})

plugins.unshift(new HtmlWebpackPlugin({
	favicon: dirPath.src+'/favicon.ico',
	filename:'index.html',   
	template: dirPath.src + '/index.html',
	inject:'body',    //插入的位置 ['head','body']
	chunks:['runtimechunk~main','vendors','vue','main'],    //只允许加载当前的chunk
	chunksSortMode:'auto',  //加载chunk的顺序
	excludeChunks:[]     , //排除某个 chunk
}))

module.exports = {
    entry: entry,
    plugins: plugins
}

修改build/entry.js

- const dirPath = require('./base/path');
+ const html = require('./base/html');

- let entry = {
-  main: dirPath.src + '/index.js'
-}

+ let entry = html.entry

module.exports = entry;

修改build/plugin.js

const dirpath = require('./base/path');
const config = require('./base/config');
+ const html = require('./base/html');

const webpack = require('webpack');
- const HtmlWebpackPlugin = require('html-webpack-plugin');    //生成html文件
const { CleanWebpackPlugin } = require('clean-webpack-plugin');  //清除
const MiniCssExtractPlugin = require("mini-css-extract-plugin");  //css样式提取
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');
+ const fs = require('fs');



let plugins = [
-	new HtmlWebpackPlugin({
-		title: '瓦力博客',
-		template: dirpath.src + '/index.html'   //以src/index.html为编译模板
-	}),
	new  MiniCssExtractPlugin({
		filename: config.NODE_ENV == 'development'?'[name.css]': `${dirpath.css}/[name].[hash].css`,
		chunkFilename: config.NODE_ENV == 'development'?'[id].css': `${dirpath.css}/[id].[hash].css`
	}),   //css提取
	new webpack.ProvidePlugin({
		_:'loadsh',
		url: ['../src/api/apipath', 'url']
	}),
	new webpack.DefinePlugin({ 
		IS_PRODUCTION: config.NODE_ENV == 'development'?JSON.stringify(false):JSON.stringify(true),
	}),
	new CleanWebpackPlugin()
]

+ plugins = html.plugins.concat(plugins);

let files = fs.readdirSync(dirpath.dll);
files.forEach(val=>{
	if(/\.js$/.test(val)){
		plugins.push(new AddAssetHtmlPlugin({ 
			filepath: `${dirpath.dll}/${val}`
		}))		
	}

	if(/\.json$/.test(val)){
		plugins.push(new webpack.DllReferencePlugin({
			manifest: `${dirpath.dll}/${val}`
		}))
	}
})


if('development' == config.NODE_ENV){
	plugins.push(new webpack.HotModuleReplacementPlugin());
}

module.exports = plugins;

运行build

yarn run build

ssl

可以看到cli有三个入口文件,检查dist是不是生成三个html文件

dist
|-index.html
|-page
  |-login
    |-login.html
  |-logout
    |-logout.html

打开生成html,检查引入的文件是否正确

dist/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>title</title>
<link rel="shortcut icon" href="/favicon.ico"></head>
<body>
<h1>欢迎来到瓦力博客</h1>
<span class="iconfont wali-icon-fuzhi"></span>
<img src="assets/images/wali_logo2BQg9e7.png" alt="">
<script type="text/javascript" src="/vue.dll.js"></script><script type="text/javascript" src="/vendors.dll.js"></script><script type="text/javascript" src="/runtimechunk~main.js"></script><script type="text/javascript" src="/main.js"></script></body>
</html>

dist/page/login/login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
<link rel="shortcut icon" href="/favicon.ico"></head>
<body>
    <h1>这是一个登陆页面</h1>
<script type="text/javascript" src="/vue.dll.js"></script><script type="text/javascript" src="/vendors.dll.js"></script><script type="text/javascript" src="/runtimechunk~login.js"></script><script type="text/javascript" src="/login.js"></script></body>
</html>

dist/page/logout/logout.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
<link rel="shortcut icon" href="/favicon.ico"></head>
<body>
    <h1>退出登录</h1>
<script type="text/javascript" src="/vue.dll.js"></script><script type="text/javascript" src="/vendors.dll.js"></script><script type="text/javascript" src="/runtimechunk~logout.js"></script><script type="text/javascript" src="/logout.js"></script></body>
</html>

可以看到对应的js文件都引入成功了,到此webpack常用的基本配置就算完成了。小菜会将代码上传到github上,供大家参考。

webpack4.x 教程

webpack 准备工作(1) webpack 手写最基本的配置(2) webpack 打包样式(3) webpack 让打包更便捷(4) webpack 打包图片(5) webpack iconfont打包(6) webpack devServer本地开发(7) webpack 处理ES6语法(8) webpack SourceMap配置(9) webpack Tree Shaking(10) webpack js代码分割(11) webpack 懒加载(12) webpack 打包分析,Preloading,Prefetching(13) webpack 模块化区分开发和生产(14) webpack 样式文件的代码分割(15) webpack 浏览器缓存(16) webpack shimming(17) webpack 环境变量(18) webpack Esline(19) webpack 解析resolve(20) webpack Library的打包(21) webpack dll(22) webpack 多页面打包配置(23) webpack 搭建vue脚手架(24)