在实际项目中,每次对项目打包后我们都需要手动在index.html添加js,当打包后的js入口文件名更改时,我们又需要再一次修改index.html中的js,有没有觉得很麻烦,现在有一个插件来帮助我们,打包完之后自动生成HTML文件,并自动引入打包后的js文件。
1、安装依赖
npm i html-webpack-plugin html-loader --save-dev
package.json如下:
{
"name": "webpack_test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "webpack --mode development",
"build": "webpack --mode production"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.6.4",
"@babel/plugin-transform-runtime": "^7.6.2",
"@babel/polyfill": "^7.6.0",
"@babel/preset-env": "^7.6.3",
"@babel/runtime": "^7.6.3",
"babel-loader": "^8.0.6",
"clean-webpack-plugin": "^3.0.0",
"core-js": "^3.3.2",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"jquery": "^3.4.1",
"lodash": "^4.17.15",
"react": "^16.10.2",
"webpack": "^4.41.2",
"webpack-bundle-analyzer": "^3.6.0",
"webpack-cli": "^3.3.9"
}
}
解释一下html-webpack-plugin和html-loader的作用:
html-webpack-plugin插件用于根据配置自动生成html文件,并将打包后的js入口文件自动引入到生成的html中。如果有多个入口文件,它们都会被引入到html中。如果在webpack输出中含有任何的css文件(例如,用mini-css-extract-plugin提取的css),这些文件将包含在html头中的标签中。
参考:https://github.com/jantimon/html-webpack-plugin
html-loader加载器用于html-webpack-plugin在根据html模板生成html时加载html模板。
参考:https://github.com/webpack-contrib/html-loader
html-webpack-plugin和html-loader之间没有任何依赖关系
2、配置webpack.config.js
const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: {
main: './lazyloading/index.js'
},
output: {
path: path.resolve(__dirname, 'build'), // 打包文件的输出目录
filename: '[name].bundle.js', // 代码打包后的文件名
publicPath: __dirname + '/build/', // 引用的路径或者 CDN 地址
chunkFilename: '[name].js' // 代码拆分后的文件名
},
module: {
rules: [{
test: /\.html$/,
use: [{
loader: 'html-loader'
}]
}]
},
// 拆分代码配置项
optimization: {
splitChunks: {
chunks: 'all',
minSize: 30000,
maxSize: 0,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',
name: true,
cacheGroups: {
common: {
name: 'common',
minSize: 0, //表示在压缩前的最小模块大小,默认值是 30kb,如果没设置为0,common模块就不会抽离为公共模块,因为原始大小小于30kb
minChunks: 2, // 最小公用次数
priority: 5, // 优先级
reuseExistingChunk: true // 公共模块必开启
},
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
},
plugins: [
new CleanWebpackPlugin(), // 会删除上次构建的文件,然后重新构建
new BundleAnalyzerPlugin(),
new HtmlWebpackPlugin({
// 打包输出HTML
title: '自动生成 HTML',
minify: {
// 压缩 HTML 文件
removeComments: true, // 移除 HTML 中的注释
collapseWhitespace: true, // 删除空白符与换行符
minifyCSS: true // 压缩内联 css
},
filename: 'index.html', // 生成后的文件名
template: path.resolve(__dirname, 'index.html'), // 根据此模版生成 HTML 文件
chunks: ['main'] // entry中的 main 入口才会被打包
})
]
}
主要是在配置中引入html-loader加载器和html-webpack-plugin插件。
由于使用了 title 选项,则需要在template选项对应的 html的 title 中加入
3、打包并测试
运行cnpm run build
打包后生成了index.html文件,打开index.html文件发现title部分并没有根据配置改变,这是为什么呢?
原因是因为HtmlWebpackPlugin支持html以及ejs模板语法,当在webpack中配置了html-loader后,就相当于全局设置以html模板语法进行解析,HtmlWebpackPlugin解析html模板是以string类型进行解析,而解析ejs模板是以函数类型进行解析,在全局设置了html-loader后,HtmlWebpackPlugin就不会认识ejs语法了,只会将它当成string直接输出。
参考:
https://blog.csdn.net/kai_vin/article/details/88722662
https://segmentfault.com/q/1010000004555431
现在有两种解决方法:
注释掉配置中添加的html-loader,HtmlWebpackPlugin会默认采用函数类型去解析模板。
将html模板改成ejs模板。
第一种方式:
注释掉以下代码
// module: {
// rules: [{
// test: /\.html$/,
// use: [{
// loader: 'html-loader'
// }]
// }]
// },
打包执行:
第二种方式:
细心的朋友可能还会发现引入js入口文件的地址是一个绝对地址,但是真实项目需要部署到服务器,使用绝对地址肯定不行的,因为服务器是不可能找得到电脑本地的文件。
所以,我们要将引入的绝对路径改成相对路径,修改publicPath即可,该字段表示引用的路径
修改webpack.config.js:
output: {
path: path.resolve(__dirname, 'build'), // 打包文件的输出目录
filename: '[name].bundle.js', // 代码打包后的文件名
publicPath: __dirname + '/build/', // 引用的路径或者 CDN 地址
chunkFilename: '[name].js' // 代码拆分后的文件名
},
改成:
output: {
path: path.resolve(__dirname, 'build'), // 打包文件的输出目录
filename: '[name].bundle.js', // 代码打包后的文件名
publicPath: './', // 引用的路径或者 CDN 地址
chunkFilename: '[name].js' // 代码拆分后的文件名
},