以下皆为拉勾教育课件内笔记
打包 HTML
生成 HTML
html-webpack-plugin,该插件用来创建 HTML 文件,创建的 HTML 文件默认引⼊打包后的所有资源文件。复制 HTML 到打包目录、确保 HTML 中的路径正确(例如:HTML 标签中的 src )详情查看:https://www.npmjs.com/package/html-webpack-plugin
安装:
npm i html-webpack-plugin -D # webpack 5
npm i html-webpack-plugin@4 -D # webpack 4
引入:
const HtmlWebpackPlugin = require('html-webpack-plugin')
配置:
在 webpack.config.js 的 plugins 插件中添加 HtmlWebpackPlugin
plugins: [
new HtmlWebpackPlugin() // 添加这⼀⾏
]
执行命令:
webpack
设置 HTML模板
plugins: [
// ⽤于⽣成 index.html
new HtmlWebpackPlugin({
template: './src/index.html', // 指定 HTML 的模板
})
]
声明模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="<%= htmlWebpackPlugin.options.vi ewport %>">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Demo</title>
</head>
<body>
<div class="container">
<h1>Hello Webpack</h1>
</div>
</body>
</html>
设置 HTML 配置项
少量配置可以在 HtmlWebpackPlugin 中指定
大量配置建议指定 HTML 文件的模板
plugins: [
// ⽤于⽣成 index.html
new HtmlWebpackPlugin({
template: './src/index.html', // 指定 HTML 的模板
title: 'Webpack Plugin Sample', // 添加 HTML 的 title
meta: { // 添加 HTML 的 meta
viewport: 'width=device-width, initial-scale=1.0'
}
}),
// ⽤于⽣成 about.html
new HtmlWebpackPlugin({
filename: 'about.html' // 指定声明的⽂件名,如果有多个模板,可以实例化多次
})
]
声明 HTML 模板(其中的变量比如 title 使用 EJS 语法)
EJS -- 嵌入式 JavaScript 模板引擎 | EJS 中文文档 (bootcss.com)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="<%= htmlWebpackPlugin.options.vi ewport %>">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div class="container">
<h1><%= htmlWebpackPlugin.options.title %></h1>
</div>
</body>
</html>
压缩 HTML
除了创建模板文件外,htmlWebpackPlugin 还可以通过配置,实现压缩 HTML 的效果,minify 选项可以配置压缩的内容。
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: "./src/index.html",
title: "Webpack Demo666",
minify:{
removeRedundantAttributes: true, // 删除多余的属性
collapseWhitespace: true, // 折叠空⽩区域
removeAttributeQuotes: true, // 移除属性的引号
removeComments: true, // 移除注释
collapseBooleanAttributes: true // 省略只有 boolean 值的属性值 例如:readonly checked
}
}),
]
打包 JS
编译
babel
安装 babel-loader:npm install babel-loader @babel/core @babel/preset-env -D
@babel/core 包含 Babel 转换的核⼼ API
@babel/preset-env 包含最新 JS 语法的转换规则
babel-loader Webpack 中,转换 JS 的加载器
babel 结构:
添加配置:
启用 babel-loader 后 ES6+ 的语法会转成 ES5。但是 babel 只会对基本语法进行转移。像 promise 这样的高级语法,Babel 就不能转换。
const path = require('path')
module.exports = {
mode: 'none',
entry: './src/main.js',
output: {
filename: 'bundle.js',
path: path.join(__dirname, 'dist'),
publicPath: 'dist/'
},
module: {
rules: [
{
test: /\.m?js$/i,
exclude: /node_modules/, // 排除不需要打包的⽬录
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
}
}
polyfill
安装:npm i @babel/polyfill -D
使用:在入口文件中引入 @babel/polyfill
import '@babel/polyfill'
// ......
@babel/polyfill 会对所有的 JS 新语法进行转译(没用到的新语法也会被转译),因此打包后的 JS 会 非常大
core-js
core-js 可以按需转译(即只转译用到的新语法)
安装:npm i core-js -D
使用:
const path = require('path')
module.exports = {
mode: 'none',
entry: './src/main.js',
output: {
filename: 'bundle.js',
path: path.join(__dirname, 'dist'),
publicPath: 'dist/'
},
module: {
rules: [
{
test: /\.m?js$/i,
exclude: /node_modules/, // 排除不需要打包的⽬录
use: {
loader: 'babel-loader',
options: {
// presets: ['@babel/preset-env']
presets: [
'@babel/preset-env',
{
// 按需加载
useBuiltIns: 'usage',
// 指定 core-js版本
corejs: {
version: 3
},
// 指定兼容性做到哪个版本浏览器
targets: {
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]
}
}
}
]
}
}
格式校验
之前进行格式校验使用的是 eslint-loader,但 eslint-loader 已经废弃。
现在推荐使用 eslint-webpack-plugin 来进行 JS 的格式校验
详情查看:https://www.npmjs.com/package/eslint-webpack-plugin
安装:npm i eslint eslint-config-airbnb-base eslint-webpack-plugin eslint-plugin-import -D
说明
eslint(用来对 JS 进行格式校验的工具)
eslint-config-airbnb-base(格式校验规则)
eslint-webpack-plugin(Webpack 的 eslint 插件)
eslint-plugin-import(⽤于在 package.json 中读取 eslintConfig 配置项)
使用:
const ESLintPlugin = require('eslint-webpack-plugin');
module.exports = {
// ...
plugins: [new ESLintPlugin(options)],
// ...
};
设置配置项:
const ESLintPlugin = require('eslint-webpack-plugin');
module.exports = {
plugins: [
# 使⽤ 配置项都可以在 eslint-webpack-plugin 的 github 上找到
new ESLintPlugin({
fix: true,
extensions: ['js', 'json', 'coffee'],
exclude: '/node_modules/'
}),
]
};
指定 eslint 配置:
指定 eslint 配置的方式有多种
- 在 package.json 中,通过 eslintConfig 指定
- 在项目根目录下,通过 .eslintrc 指定(.eslintrc 可以通过 eslint --init 命令生成)
// package.json
"eslintConfig": {
"extends": "airbnb-base",
#!!!!如果没使⽤ alias 下⾯的不⽤配置!!!!!
"settings": {
"import/resolver": {
"webpack": {
"config": "webpack.config.js"
}
}
}
}
打包图片
样式中的图片引入
打包图片时,最常用两个 loader
- file-loader 将用到的图片直接复制到 dist 目录下,过滤掉不用的图片
https://www.npmjs.com/package/file-loader - url-loader 将小于指定大小的图片,转成 base64,超过指定大小的图片依然使用 file-loader 进行复制,转成 base64 字符串后,图片会跟 js 一起加载(减少图片的请求次数)
https://www.npmjs.com/package/url-loader
安装:npm install file-loader url-loader -D
配置:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
// 打包模式
mode: 'development',
// ⼊⼝⽂件
entry: './src/index.js',
// 输出
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'main.bundle.js',
},
// loader 配置
module: {
rules: [
{
test: /\.(png|gif|jpe?g)$/,
use: {
loader: 'url-loader',
options: {
limit: 2 * 1024, // 2 kb 设置图⽚⼤⼩,⼩于该数值的图⽚会被 转成 base64
// 保留原图片名称及后缀名
name: "images/[name].[ext]" // [name] 是原名称,[ext]是原后缀名
}
},
}
]
},
// plugin 配置
plugins: [
new HtmlWebpackPlugin({
title: "Webpack Demo",
template: "./src/index.html"
})
]
};
上述配置可以处理样式文件中的图片引入,例如:
body {
/* background-color: #dbf; */
background: url(./images/1.jpg) no-repeat;
}
HTML 中的图片引入
html-loader 将 HTML 导出为字符串(负责引入 img,从而能被 url-loader 进行处理)
https://www.npmjs.com/package/html-loader
安装:npm install html-loader -D
配置:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
// 打包模式
mode: 'development',
// ⼊⼝⽂件
entry: './src/index.js',
// 输出
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'main.bundle.js',
},
// loader 配置
module: {
rules: [
{
test: /\.(png|gif|jpe?g)$/,
use: {
loader: 'url-loader',
options: {
limit: 2 * 1024, // 2 kb
name: "images/[name].[ext]",
// url-loader 默认采⽤ ES Module 进⾏解析,⽽ html-loader 引⼊图⽚使⽤的是 CommonJS
// 解决:关闭 url-loader 的 ES Module 解析,使⽤ CommonJS 进⾏解析
esModule: false
}
},
},
{
test: /\.(htm|html)$/i,
// 负责处理 HTML 中的 img 图⽚
loader: 'html-loader',
options: {
// webpack4 中只需要在 url-loader 配置 esModule:false
// webpack5 需要 html-loader 也配置 esModule:false
esModule: false
}
}
]
},
// plugin 配置
plugins: [
new HtmlWebpackPlugin({
title: "Webpack Demo",
template: "./src/index.html"
})
]
};
html-loader 与 html-webpack-plugin 冲突
问题:
入口页面中默认使用的 lodash 模板未被解析⽣效。 虽然 html-loader 可以解决 HTML 文件中的图片加载问题,但 HTML 中的 ejs 语法失效了。
原因:
htmlWebpackPlugin 会检查目标文件是否已经有 loader 处理,如果有其他 loader 处理, htmlWebpackPlugin 不再使用 lodash.template 去编译目标,直接返回 source。
这里,我们已经声明了通过 html-loader 来处理 html 文件,因此 ejs 语法失效
部分 htmlWebpackPlugin 的关键代码(位置:html-webpack-plugin/lib/loader.js)
const _ = require('lodash');
module.exports = function (source) {
// Get templating options
const options = this.getOptions();
const force = options.force || false;
const allLoadersButThisOne = this.loaders.filter((loader) => lo ader.normal !== module.exports);
// 如果有其他 loader 进⾏处理,则直接返回
if (allLoadersButThisOne.length > 0 && !force) {
return source;
}
// 否则使⽤ lodash.template 的模板进⾏语法解析
const template = _.template(source, {
interpolate: /<%=([\s\S]+?)%>/g,
variable: 'data', ...options
});
解决:
将模板文件统一为 ejs 格式,先通过 htmlWebpackPlugin 处理 ejs 文件,然后 html-loader 继续做后续处理。
修改模板⽂件后缀(src/index.html => src/index.ejs)
-
修改配置中的模板名称
plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ template: "./src/index.ejs", // 这⼀⾏ title: "Webpack Demo", }) ]
-
将模板文件中的图片引入,改成 ejs 语法
<!-- 旧写法 --> <img src="./images/xph.gif" alt=""> <!-- 新写法 --> <img src="<%= require('./images/xph.gif') %>" alt="">