目录
Webpack 是什么?
Webpack 是一个打包器(Module bundler)。它的主要⽬标是将 JS ⽂件打包在⼀起,
打包后的⽂件⽤于在浏览器中使⽤。同时,它也能够转换 (transform)、打包 (bundle) 或包
裹 (package) 任何资源。
资源网站
官⽹:https://webpack.js.org/
中⽂官⽹:https://webpack.docschina.org/
Github:https://github.com/webpack/webpack
转化/构建
将源代码转换成⽣产代码的过程。即把不支持的代码转成支持的代码。
打包/合并
把多个文件合并成一个文件。
构建+打包
@打包工具,即为Webpack。
除了可以处理js,各类型也可以。
综上,Webpack的功能是
- 将多个⽂件合并(打包),减少 HTTP 请求次数,从⽽提⾼效率
- 对代码进⾏编译,确保浏览器兼容性
- 对代码进⾏压缩,减⼩⽂件体积,提⾼加载速度
- 检测代码格式,确保代码质量
- 提供热更新服务,提⾼开发效率
Webpack 概述
Webpack 核心概念
- ⼊⼝(Entry) 第一个被访问的源码文件 默认src/index.js
- 出⼝(Output)打包后的输出文件 默认dist/main.js
- 加载器(Loader)专门用来处理一类(非js)的工具
- 命名方式 xxx-loader (css/html/file)
- 常用加载器:https://www.webpackjs.com/loaders/
- 插件(Plugins)实现除 loader 之外的其他功能
- 命名⽅式:xxx-webpack-plugin
- 常用插件:https://www.webpackjs.com/plugins/
- 模式(Mode)区分环境
- development(开发环境:⾃动优化打包速度,添加⼀些调试过程中的辅助)
- production(⽣产环境:⾃动优化打包结果)
- none(运⾏最原始的打包,不做任何额外处理)
- 模块(Module)
- 依赖图(Dependency Graph)
Webpack 最快上手
Webpack 配置文件
配置⽂件是⽤来简化命令⾏选项的
配置前:webpack ./src/index.js --output-path ./dist --mode=development
配置后:webpack
默认的配置⽂件名称是 webpack.config.js
使⽤ Webpack 的过程,⼤部分就是跟配置⽂件打交道的过程
配置详情: https://www.webpackjs.com/configuration/
# 常用配置(需熟记)
/**
* Webpack 的配置文件
*/
const { resolve } = require('path')
module.exports = {
// 打包模式
mode: 'production',
// 入口文件
entry: './src/index.js',
// 出口配置
output: {
// 输出目录(输出目录必须是绝对路径)
path: resolve(__dirname, 'output'),
// 输出文件名称
filename: 'bundle.js'
},
// 模块配置
module: {
rules: [
// 指定多个配置规则
]
},
// 开发服务器
devServer: {
},
// 插件配置
plugins: [
]
}
Webpack 基础
打包 css
Loader 使用方式:
- 在入口文件中以模块方式 import 引入css
- 然后在 webpack.config.js 中,在 module 处添加 .css 文件的配置规则(注意各个 loader 的使用顺序 由下往上,由右往左)
module: {
// 配置⽂件类型规则,不同的规则使⽤不同的 loader 进⾏处理
rules: [
{
// test 后跟随正则表达式,匹配⽂件类型
test: /\.css$/,
// use 表示使⽤什么 loader 来处理上述类型的⽂件
use: [
// 2. 将 JS 中的样式⽂件,嵌⼊到⻚⾯的 style 标签中
'style-loader',
// 1. css-loader 将样式⽂件转成 CommonJS 模块,加载到 JS 中
'css-loader'
]
}
]
}
插件使用方式:
- 需要在 webpack.config.js 最前面通过 require 引入,在 module 处配置规则
- 并在 plugins 处进行插件配置,实例化。
const { resolve } = require('path')
// 将 css 打包成独立文件
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
// 格式校验
const StylelintPlugin = require('stylelint-webpack-plugin')
// 压缩 css
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
module.exports = {
...,
module: {
rules: [
{
test: /\.css$/i,
// use 中 loader 的加载顺序:先下后上
use: [
// 3. 将 JS 中的样式,挂载到 <style> 标签中
// 'style-loader',
// 3. 将 CSS 打包到独立的文件中
MiniCssExtractPlugin.loader,
// 2. css-loader 按照 CommonJS 规范,将样式文件,输出到 JS 中
'css-loader',
// 1. 通过 postcss-loader 给样式属性添加浏览器前缀
'postcss-loader'
]
},
{
test: /\.less$/i,
// use 中 loader 的加载顺序:先下后上
use: [
// 4. 将 JS 中的样式,挂载到 <style> 标签中
// 'style-loader',
// 4. 将 CSS 打包到独立的文件中
MiniCssExtractPlugin.loader,
// 3. css-loader 按照 CommonJS 规范,将样式文件,输出到 JS 中
'css-loader',
// 2. 兼容性补全前缀
'postcss-loader',
// 1. 将 less 转成普通的 CSS
'less-loader'
]
},
{
test: ,
use: ['','']
} // 可以指定多个配置规则
]
},
// 插件配置
plugins: [
new MiniCssExtractPlugin({
filename: 'css/[name].css'
}),
new StylelintPlugin({
// 指定需要进行格式校验的文件
files: ['src/css/*.{css,less,sass,scss}']
}),
// 压缩 CSS
new OptimizeCssAssetsPlugin()
]
}
额外配置项:
1. 将 css 打包成独立文件的插件 MiniCssExtractPlugin ----》 图片路径变动问题
// 原写法
rules: [
{
test: /\.css$/i,
use: [
// 3. 将 CSS 打包到独立的文件中
MiniCssExtractPlugin.loader,
]
}
]
// 改成
rules: [
{
test: /\.css$/i,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../' // 为背景图⽚指定路径
}
}
]
}
]
2. 兼容 添加前缀 ----》 需要对 postCss 进行配置,⽤来设置 autoprefixer 的设置标准(即需要指定兼容哪些浏览器)
- 添加 PostCSS 的配置 - 在项⽬根⽬录下添加 postcss.config.js
module.exports = { 'plugins': [ require('autoprefixer') ] }
- 在 package.json 中指定好兼容规则 https://www.npmjs.com/package/browserslist
"browserslist": [ "last 1 version", "> 1%" ]
3. 配置 StyleLint 的校验规则
在 package.json 中指定好规则,使⽤ stylelint-config-standard 规则来检测代码
"stylelint": {
"extends": "stylelint-config-standard",
// 除了使⽤ stylelint-config-standard,我们还可以在 rules 字段中⾃定义校验规则
// 如果不需要⾃定义规则,可以忽略 rules
"rules": {
"number-leading-zero": "never"
}
}
关于安装:
- css-loader 负责遍历 CSS ⽂件,将 CSS 转化为 CommonJS(将 CSS 输出到打包后的JS ⽂件中)
- style-loader 负责把包含 CSS 内容的 JS 代码,挂载到⻚⾯的 style 标签当中
npm i css-loader style-loader -D
- 转换 Less
npm i less less-loader -D
- 将 CSS 打包成独立文件:mini-css-extract-plugin 插件
npm install mini-css-extract-plugin -D
- 添加前缀,解决兼容问题
- postcss-loader
- autoprefixer
npm install postcss-loader autoprefixer -D
- 校验样式
- stylelint 校验样式⽂件的命令 运行工具
- stylelint-config-standard 校验样式⽂件的规则 推荐配置
- stylelint-webpack-plugin 在 Webpack 中使⽤ stylelint 的插件
npm i stylelint stylelint-config-standard stylelint-webpack-plugin -D
- 压缩 CSS 使用 optimize-css-assets-webpack-plugin 插件
npm install optimize-css-assets-webpack-plugin -D
打包 HTML
使用插件 html-webpack-plugin。
跟上面的方法一样,在 webpack.config.js 中 require 这个插件,配置:
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
...,
plugins: [
new HtmlWebpackPlugin() // 添加这⼀⾏
]
}
可以在实例化的时候,进行 HTML 模板的设置。
plugins: [
// Html 的配置
new HtmlWebpackPlugin({
// 指定打包后的文件名称
filename: 'index.html',
// 用来指定,生成 HTML 的模板
template: './src/index.html',
// 指定 HTML 中使用的变量
title: "Webpack Demo"
}),
new HtmlWebpackPlugin({
// 指定打包后的文件名称
filename: 'about.html',
// 用来指定,生成 HTML 的模板
template: './src/index.html',
// 指定 HTML 中使用的变量
title: "关于我们",
// 还可以在这里设置压缩
minify: {
collapseWhitespace: true, // 折叠空⽩区域
keepClosingSlash: true,
removeComments: true, // 移除注释
removeRedundantAttributes: true, // 删除多余的属性
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
useShortDoctype: true
}
})
]
HTML 模板长这个样子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<h1>Hello Webpack</h1>
<a href="index.html">首页</a>
<a href="about.html">关于</a>
</body>
</html>
打包 JS
1. 为了保证 JS 在低版本浏览器的兼容性。
安装 babel-loader
- @babel/core 包含 Babel 转换的核⼼ API
- @babel/preset-env 包含最新 JS 语法的转换规则 (只能转译基本语法)
- babel-loader 是 Webpack 中,转换 JS 的加载器
npm install babel-loader @babel/core @babel/preset-env -D
// 按需转译 JS 新语法
npm i core-js -D
配置 webpack.config.js
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
// 按需加载
useBuiltIns: 'usage',
// core-js 的版本
corejs: 3,
// targets: "defaults"
// 指定兼容浏览器的版本
targets: {
chrome: '58',
ie: '9',
firefox: '60',
safari: '10',
edge: '17'
}
}
]
]
}
}
}
]}
2. 格式校验 eslint-webpack-plugin
- eslint(⽤来对 JS 进⾏格式校验的⼯具)https://eslint.org/
- eslint-config-airbnb-base(格式校验规则)
- eslint-webpack-plugin(Webpack 的 eslint 插件)
- eslint-plugin-import(⽤于在 package.json 中读取 eslintConfig 配置项)
npm i eslint eslint-config-airbnb-base eslint-webpack-plugin eslint-plugin-import -D
实例化 webpack.config.js
const ESLintPlugin = require('eslint-webpack-plugin');
module.exports = {
// ...
plugins: [
// new ESLintPlugin(options)
new ESLintPlugin({
// 自动解决常规的代码格式报错
fix: true
})
],
// ...
};
指定 ESLint 配置 package.json
"eslintConfig": {
"extends": "airbnb-base"
}
在js文件中,若要对某行不检查,采用如下注释。那么它的下一行就会跳过。
// eslint-disable-next-line
const showMsg = () => {
// eslint-disable-next-line
alert('Hello');
};
打包图片
- file-loader 将用到的图片直接复制到 dist 目录下,过滤掉不⽤的图⽚
- url-loader 将小于指定大小的图片,转成 base64,超过指定大小的图片依然使用 file-loader 进行复制
npm install file-loader url-loader -D
入口文件 index.js
// 以模块的方式引入图片
import boy from './image/xph.gif';
import homeIcon from './image/icon/home-blue.png';
const img = new Image();
img.src = boy;
document.body.append(img);
实例化 webpack.config.js
const ESLintPlugin = require('eslint-webpack-plugin');
module.exports = {
// ...
module: {
rules: [
{
test: /\.(png|gif|jpe?g)$/i,
use: {
loader: "url-loader",
options: {
// 指定图片大小,小于该数值的图片,会被转成 base64
limit: 8 * 1024, // 8 kb
// [name] 是图片原来的名称
// [ext] 是图片原来的后缀名
name: "image/[name].[ext]",
// url-loader 默认采用 ES Modules 规范进行解析,但是 html-loader 引入图片使用的是 CommonJS 规范
// 解决:关闭 url-loader 默认的 ES Modules 规范,强制 url-loader 使用 CommonJS 规范进行打包
// esModule: false
}
}
// 使用资源模块
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024
}
},
generator: {
filename: "image/[name][ext]"
}
}
// {
// test: /\.(htm|html)$/i,
// use: {
// loader: 'html-loader',
// options: {
// // Webpack 4 中只需要在 url-loader 配置 esModule: false
// // Webpack 5 需要 html-loader 中,也配置 esModule: false
// esModule: false
// }
// }
// }
};
能不能处理 HTML 中的 img 图片?
html-loader (将html导出为字符串,从而能被url-loader处理)适合处理没有使用ejs模板的html,这样就不会与 HtmlWebpackPlugin 冲突(不然它们会对同一份html起冲突,<img src="">与ejs语法)。
- 所以,只需将 index.html 改为 index.ejs,然后把 plugins 中的模板名称对应替换。
- 同时,<img src="<%= require('./image/icon/ok-black.png') %>" >
<!-- 旧写法 -->
<img src="./images/xph.gif" alt="">
<!-- 新写法 -->
<img src="<%= require('./images/xph.gif') %>" alt="">
这样,这份模板既可以被 HtmlWebpackPlugin 解析成功,又可以进行 url-loader 的处理,将图片替换成base64字符串。
打包字体
下载字体文件到fonts文件夹中。然后在css文件里添加该字体样式,再去html里引用该class。
配置 loader
{
test: /\.(eot|svg|ttf|woff|woff2)$/i,
use: {
loader: 'file-loader',
options: {
name: 'fonts/[name].[ext]'
}
}
}
两个常用插件
不需要处理的其他⽂件,可以直接复制到输出⽬录
每次打包之前,先删除输出⽬录中的历史⽂件(保证输出⽬录中的打包⽂件是最新的)
实例化 webpack.config.js
const CopyWebpackPlugin = require('copy-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = {
// ...
plugins: [
// 直接将 src 下,不需要特殊处理的文件,直接复制到输出目录中
new CopyWebpackPlugin({
patterns: [
{
from: "src/public",
to: "public"
}
]
}),
// 打包之前,先删除历史文件
new CleanWebpackPlugin(),
],
// ...
};
资源模块 Asset Modules
Webpack 5 提供了⼀个新的特性 - 资源模块。
通过资源模块也可以加载图⽚或字体,⽽⽆需配置额外的 loader。
怎么用?
module.exports = {
module: {
rules: [
// 处理图片
{
test: /\.(png|gif|jpe?g)$/i,
// use: {
// loader: "url-loader",
// options: {
// // 指定图片大小,小于该数值的图片,会被转成 base64
// limit: 8 * 1024, // 8 kb
// // [name] 是图片原来的名称
// // [ext] 是图片原来的后缀名
// name: "image/[name].[ext]",
// }
// }
// 使用资源模块
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024
}
},
generator: {
filename: "image/[name][ext]"
}
},
// 匹配字体文件
{
test: /\.(eot|svg|ttf|woff|woff2)$/i,
// use: {
// loader: 'file-loader',
// options: {
// name: 'fonts/[name].[ext]'
// }
// }
// 使用资源模块处理字体文件
// asset 可以在 asset/resource 和 asset/inline 之间进行选择
// 如果文件小于 8kb,则使用 asset/inline 类型
// 如果文件大于 8kb,则使用 asset/resource 类型
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024
}
},
generator: {
filename: "fonts/[name][ext]"
}
}
]}}
开发服务器 Dev Server
# 安装
npm i webpack-dev-server -g
# 运行
# webpack 4
webpack-dev-server ...
# webpack 5
webpack server ...
Webpack Dev Server 将打包内容放到内存中(而非磁盘),内存的读写性能远⼤于磁盘,因此
Webpack Dev Server 的热更新效率⼤于 browser-sync。(也因此不会生成 output 文件)
配置 webpack.config.js
// 开发服务器
devServer: {
// 指定加载内容的路径
contentBase: resolve(__dirname, 'output'),
// 启用 gzip 压缩
compress: true,
// 端口号
port: 9200,
// ⾃动打开浏览器
open: true,
// 启动自动更新(禁用 hot)
liveReload: true,
// 配置代理:解决接口跨域问题
proxy: {
// http://localhost:9200/api
'/api': {
// http://localhost:9200/api/users => https://api.github.com/api/users
target: 'https://api.github.com',
// http://localhost:9200/api/users => https://api.github.com/users
pathRewrite: {
'^/api': ""
},
// 不能使用 localhost:9200 作为 github 的主机名
changeOrigin: true
}
}
},
// 配置目标 写在外面,热更新的target
target: "web",