功能介绍
是一个静态资源打包工具,以一个或者多个文件作为打包入口,将我们整个项目的所有文件编译合成一个或多个文件输出出去,将浏览器不识别的语法编译成浏览器能够识别的语法
webpack使用
-
创建package.json文件,用于管理项目的信息、库依赖等
npm init
-
安装局部的webpack
// webpack-cli 是指 webpack 的指令 npm install webpack webpack-cli -D
执行webpack命令: npx webpack
// 指定生产模式下编译main.js文件 npx webpack ./src/main.js --mode=prodution
-
创建webpack.dev.js 和 webpack.prod.js 文件,并在package.json中创建scripts启动脚本
"scripts": { "dev": "webpack serve --config ./config/webpack.dev.js", "build": "webpack --config ./config/webpack.prod.js" }
-
webpack基本配置
const path = require("path"); module.exports = { // 必填 webpack执行构建入口,由1个或多个文件组成 entry: "./src/index.js", output: { // 将所有依赖的模块合并输出到main.js filename: "main.js", // 输出文件的存放路径,必须是绝对路径 path: path.resolve(__dirname, "./dist") }, // 加载器 module: {}, // plugins配置 plugins: [], // 开发服务器 自动监视文件, 自动进行编译, 不会输出打包资源, 在内存中进行编译 devServer: {}, // 模式 mode: "development",
基本配置
5大核心概念
- entry (入口) 指示webpack从哪个文件开始打包
- output(输出)指示webpack打包完输出到哪里
- loader(加载器)webpack本身只能处理js、json等资源,其他需要借助loader、webpack才能解析
- plugins(插件)扩展webpack的功能
- model (模式) 主要由【开发模式development】、【生产模式production】
loader配置
加载 CSS 图片 js文件
// 下载 style-loader css-loader sass-loader sass stylus-loader
npm install style-loader css-loader
// 在webpack配置中使用
module:{
// loader的配置
rules:[
{
// 每个文件只能被其中一个loader配置处理
oneOf: [
{
test: /\.css$/, // 检测.css文件
use: [
// 执行顺序,从左到右,从下到上
"style-loader", // 将js 中css通过创建style标签添加到html文件中
"css-loader", // 将css资源编译成commonjs的模块添加到js中
]
},
{
test: /\.s[ac]ss$/, // 检测.sass 或 .scss文件
use: [
"style-loader",
"css-loader",
"sass-loader" // 将sass编译成css
]
},
{
test: /\.styl$/, // 检测.styl文件
use: [
"style-loader",
"css-loader",
"stylus-loader" // 将stylus编译成css
]
},
{
test: /\.(png|jpe?g|gif|webp|svg)$/,
type: "asset",
parser: {
dataUrlCondition: {
// 小于10kb的图片转base64
maxSize: 10 * 1024, // 10kb
}
},
generator: {
// 指定图片名称和位置 [hash:10]名称hash值取前10位
filename: "static/images/[hash:10][ext][query]"
}
},
{
// 处理图标配置以及其他资源
test: /\.(eot|svg|ttf|woff|woff2|map3|avi|map4)$/,
type: 'asset/resource', // 当做静态资源直接复制文件
generator: {
filename: 'static/font/[hash:10][ext][query]' // 放到dist/font文件夹, 文件名格式如左
}
},
{
test: /\.?js$/,
// exclude: /node_modules/, // 排除node_modules中的js文件
include: path.resolve(__dirname, '../src'), // 只处理src下的文件,其它的不用处理
use: [
{
// 开启多进程
loader: "thread-loader",
options: {
works: threads // 进程数量
}
},
{
// 只能添加一个loader, use可以添加多个
loader: 'babel-loader',
options: {
// 开启Bable缓存
cacheDirectory: true,
// 关闭缓存的压缩
cacheCompression: false,
plugins: ["@babel/plugin-transform-runtime"] // 减少代码体积
}
}
]
}
]
}
],
},
Eslint:
可组装的JavaScript 和 JSX 检查工具 , Eslint 规则配置可以新建文件: .eslintrc.js 或者在pacjage.json 添加 eslintConfig: {}
// 下载包
npm install eslint eslint-webpack-plugin --save-dev
// 在webpack配置中
const ESLintPlugin = require('eslint-webpack-plugin');
plugins:[
new ESLintPlugin({
// 检查src下面的文件
context: path.resolve(__dirname, " ../src"),
exclude: "node_modules", // 默认值
cache: true, // 开启缓存
cacheLocation: path.resolve(__dirname, '../node_modules/.cache/eslintcache'), // 缓存的路径
threads, // 开启多进程和设置进程数量
}),
],
// Eslint 规则配置, 我这里是在跟目录新加的 .eslintrc.js 文件
module.exports = {
// 继承官方的Eslint规则
extends: ["eslint:recommended"],
env: {
node: true, // 启动node中的全局变量
browser: true, // 启动浏览器中的全局变量
},
parserOptions: {
ecmaVersion: 6, // es6
sourceType: "module" // es module
},
// 定义规则 0是off、1是告警、 2是错误
rules: {
"no-var": 2, // 不能使用var定义变量
},
// 允许Eslint 经行动态加载
plugins: ["import"]
}
同时可以通过在跟目录创建.eslintignore文件, 其目的是配置vscode编辑器安装了Eslint 对项目的eslint检查,这个配置定义文件名可以取消检查
// 这里直接定义文件名
dist
node_modules
注:
.eslintignore:忽略 eslint 校验
.eslintrc.js:配置 eslint 规则
Babel
用于将ES6语法编译成转换后的js语法
Babel主要用法就是添加预设
module.exports = {
presets: []
}
preser预设包含哼多,比如:
@babel/preser-env 一个智能预设,允许使用最新的js
@babel/preset-react 用来编译React jsx的语法
@babel/preset-typescript 用来编译TypeScript的语法
具体配置在跟目录创建babel.config.js
// 下载包
npm install -D babel-loader @babel/core @babel/preset-env
// 在babel.config.js配置预设
module.exports = {
// 智能预设,能够编译ES6的语法
presets: [
[
"@babel/preset-env",
{
useBuiltIns: "usage", // core.js按需自动引入
corejs: 3 // core.js版本
}
]
]
}
// webpack使用
module: {
rules: [
{
test: /\.?js$/,
// exclude: /node_modules/, // 排除node_modules中的js文件
include: path.resolve(__dirname, '../src'), // 只处理src下的文件,其它的不用处理
use:use: {
loader: 'babel-loader',
// 我这里的配置定义在 babel.config.js里面
//options: {
// presets: ['@babel/preset-env']
//}
}
}
]
}
处理html资源
html-webpack-plugin 自动在html引入打包生成的资源
// 下载包
npm install --save-dev html-webpack-plugin
// 在webpack配置中
// 打包时处理html静态资源
const HtmlWebpackPlugin = require('html-webpack-plugin');
plugins:[
new HtmlWebpackPlugin({
// 模板:以 public/index.html 文件创建新的html文件
// 新的html文件特点:1. 结构和原来的一致 2. 自动引入打包生成的资源
template: path.resolve(__dirname, "../public/index.html")
})
],
开发服务器&自动化
解决修改完代码自动进行编译
// 下载包
npm install webpack-dev-servar -D
// 在webpack配置中添加, 开发服务器 自动监视文件, 自动进行编译, 不会输出打包资源, 在内存中进行编译
devServer: {
host: "0.0.0.0", // 启动服务器的域名
port: "8089", // 启动服务器的端口
open: false, // 是否自动打开浏览器
hot: true, // 开启HMR(默认值)
// 代理
proxy: {}
},
启动指令:npx webpack serve --config ./config/webpack.dev.js
提取css文件
提取css文件将css文件生成单独文件,利用link标签引入, 能有效处理页面刚进入时的闪屏现象
// 下载包
npm install --save-dev mini-css-extract-plugin
// 在webpack中引入使用
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [new MiniCssExtractPlugin()],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
};
css 兼容性处理
// 下载包
npm install postcss-loader postcss postcss-preset-env -D
module: {
rules: [
{
test: /\.css$/i,
use: [
"style-loader",
{
loader: "css-loader",
options: { importLoaders: 1 },
},
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
[
"postcss-preset-env",
{
// Options
},
],
],
},
},
},
],
},
],
},
CSS压缩、优化处理
支持缓存和并发处理
// 下载包
npm install css-minimizer-webpack-plugin --save-dev
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
optimization: {
// 压缩的操作
minimizer: [
new CssMinimizerPlugin(),
],
},
提示开发体验
sourceMap (源文件映射),能有效让编译后的代码出错位置找到映射后源代码出错的位置
devtool: "cheap-module-source-map"
开发模式: cheap-module-source-map
优点:打包编译速度快,只包含行映射
缺点:没有列映射
生产模式: source-map (行和列都会关注)
优点:包含行、列的映射
缺点:打包编译速度慢
提升打包构建速度
(HoModuleReplacement – 热模块替换)能够在程序运行中替换、添加或删除模块,无需整个页面重新加载
devServer: {
...,
hot: true, // 开启HMR(默认值)
},
css文件在style-loader 已经具备热模块更新
js文件默认不行
// 判断是否支持热模块替换功能
if(module.hot) {
module.hot.accept("./js/main.js")
}
vue框架和reat框架有vue-loader、react-hot-loader来解决这个问提
oneOf:[]
编译打包时每个文件都会经过所有的loader处理,oneOf只匹配一个,匹配上了,后面的就不进行匹配了
Include、Exclude
开发时使用的第三方库或插件,所有文件都下载到了node_modules中,这些文件是不需要编译可以直接使用
Include:只处理包含的文件,其他文件不处理
Exclude:排除的指定文件,其他文件都处理
两个选其一,要么添加,要么排除,不然会报错
Cache
打包时js文件都要经过Eslint检查和Babel编译,速度慢,这里Cache可以将其缓存起来,第二次打包速度就快了
// Bable缓存
{
test: /\.?js$/,
// exclude: /node_modules/, // 排除node_modules中的js文件
include: path.resolve(__dirname, '../src'), // 只处理src下的文件,其它的不用处理
// 只能添加一个loader, use可以添加多个
loader: 'babel-loader',
options: {
// 开启Bable缓存
cacheDirectory: true,
// 关闭缓存的压缩
cacheCompression: false,
}
}
// Eslint缓存
new ESLintPlugin({
// 检查src下面的文件
context: path.resolve(__dirname, " ../src"),
exclude: "node_modules", // 默认值
cache: true, // 开启缓存
cacheLocation: path.resolve(__dirname, '../node_modules/.cache/eslintcache') // 缓存的路径
}),
Terser webpack内部自动引入,目的是对js文件进行压缩
Thead
当项目很庞大时,js打包速度很慢,这可以使用Thead开启多进程同时处理js文件
特别注意:仅在特别耗时操作中使用,每个进程启动就有大概600ms开销
使用thead方法
先获取cup的核数
// node核心模块
const os = require(''os");
// cup 核数
const threads = os.cpus().length;
npm install thread-loader -D
{
test: /\.?js$/,
// exclude: /node_modules/, // 排除node_modules中的js文件
include: path.resolve(__dirname, '../src'), // 只处理src下的文件,其它的不用处理
use: [
{
// 开启多进程
loader: "thread-loader",
options: {
works: threads // 进程数量
}
},
{
// 只能添加一个loader, use可以添加多个
loader: 'babel-loader',
options: {
// 开启Bable缓存
cacheDirectory: true,
// 关闭缓存的压缩
cacheCompression: false,
}
}
]
}
new ESLintPlugin({
// 检查src下面的文件
context: path.resolve(__dirname, "../src"),
exclude: "node_modules", // 默认值
cache: true, // 开启缓存
cacheLocation: path.resolve(__dirname, '../node_modules/.cache/eslintcache'), // 缓存的路径
threads, // 开启多进程和设置进程数量
}),
// 在生产模式下需要压缩处理
// 压缩js,内置插件
const TerserWebpackPlugin = require('terser-webpack-plugin')
new TerserWebpackPlugin({
parallel: threads // 开启多进程和设置进程数量
})
减少代码体积
开发时定义的工具函数库及第三方工具函数库和组件库,有很多是没有引入使用,(Tree Shaking)可以将其移除没有使用的代码
webpack生产模式下默认开启了这个功能
Babel 为编译每个文件都插入了辅助代码,使体积过大,这里将这些辅助代码作为独立模块,避免重复引用
@babel/plugin-transform-runtime:禁用了Babel自动对每个文件的runtime注入,并且所有辅助代码都在这里引用
npm install @babel/plugin-transform-runtime -D
{
// 只能添加一个loader, use可以添加多个
loader: 'babel-loader',
options: {
// 开启Bable缓存
cacheDirectory: true,
// 关闭缓存的压缩
cacheCompression: false,
plugins: ["@babel/plugin-transform-runtime"] // 减少代码体积
}
}
Image Mininizer
对图片进行压缩,减少图片的体积
npm install image-minimizer-webpack-plugin imagemin -D
注:同时下载包有两种模式,还需选择其中一种模式
// 无损压缩
npm install imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo --save-dev
// 有损压缩
npm install imagemin-gifsicle imagemin-mozjpeg imagemin-pngquant imagemin-svgo --save-dev
这里模式下载时容易下载不下来
缺失: jpegtran.exe 或者 optipng.exe
可以从官网下载后放置对应的目录下
node_modules\jpegtran-bin\vendor
node_modules\optipng-bin\vendor
优化代码运行能力
Code Split
打包时会将所有的js文件打包到1个文件,体积过大,这里将会处理对js文件进行分割,生成多个js文件,并且按需加载
打包时会先看 entry 输入口
entry js输入口有几个会默认输出几个,
其次 才看 splitChunks 配置
splitChunks: {
// 打包生成的就是chunks
chunks: 'all', // 对所有模块镜像分割
// 下面的都是默认值
// minSize: 20000, // 分割的代码最小的大小
// minRemainingSize: 0, // 确保提取的文件大小不能为0
// minChunks: 1, // 至少被引入的次数,满足条件才经行分割
// maxAsyncRequests: 30, // 按需加载时并行加载的文件最大数量
// maxInitialRequests: 30, // 入口js文件最大并行请求数量
// enforceSizeThreshold: 50000, // 超过50kb一定会单独打包 (此时会忽略 minRemainingSize、maxAsyncRequests、maxInitialRequests)
// // 哪些模块要打包到一个组
// cacheGroups: {
// defaultVendors: { // 组名
// test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模块
// priority: -10, // 权重(越大越高)
// reuseExistingChunk: true, // 如果chunk包含已从 bundle 中拆分出来的模块,将会重用,不会生成新的模块
// },
// default: {
// minChunks: 2, // 权重更大, 会覆盖上面的 minChunks
// priority: -20,
// reuseExistingChunk: true,
// },
// },
},
按需加载实现动态引入,按需加载的文件会生成出多个文件
import('./js/math').then((res)=> {
})
生成的chunk文件模块命名
output: {
chunkFilename: '/state/js/[name].js'
}
PWN
渐进式网络应用,能让web页面在断网的情况下也能访问
// 下载包
npm install workbox-webpack-plugin --save-dev
// 在webpack配置中引入 使用
const WorkboxPlugin = require('workbox-webpack-plugin');
plugins: [
new WorkboxPlugin.GenerateSW({
// 这些选项帮助快速启用 ServiceWorkers
// 不允许遗留任何旧的 ServiceWorkers
clientsClaim: true,
skipWaiting: true,
}),
]
// 最后在main.js启动 ServiceWorkers
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/service-worker.js').then(registration => {
console.log('SW registered: ', registration);
}).catch(registrationError => {
console.log('SW registration failed: ', registrationError);
});
});
}
在package.json文件中指定适配浏览器版本
"browserslist": [
"last 2 version", // 市面上流行浏览器的最近两个版本
"> 1%", // 覆盖99%的浏览器
"not dead" // 不要死掉的浏览器版本
]
webpack优化主要根据以下出发
完整版:
// node.js核心模块,用来处理路径问题
const path = require("path")
const ESLintPlugin = require('eslint-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// css 压缩处理
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
// 打包时处理html静态资源
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 获取cup核数
const os = require('os');
const threads = os.cpus().length;
// 压缩js,内置插件
const TerserWebpackPlugin = require('terser-webpack-plugin');
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
// 渐进式网络应用,能让web页面断网情况下也能访问
const WorkboxPlugin = require('workbox-webpack-plugin');
// 样式公共块
function cssCommonloader(param) {
return [
// 提取css成单独文件
MiniCssExtractPlugin.loader,
// 将css资源编译成commonjs的模块添加到js中
"css-loader",
// 注意区分位置
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env" // 能解决大多数样式兼容性问题
]
}
}
},
param
].filter(Boolean)
}
module.exports = {
// 入口 相对路径
entry: "./src/main.js",
// 输出
output:{
// 文件输出路径,__dirname是node.js的变量,代表当前文件的文件夹目录,这里需要绝对路径
path:path.resolve(__dirname, "../dist"),
// 指定输出文件名和位置
filename: "static/js/main.js",
// 打包输出的其他文件命名
chunkFilename: '/static/js/[name].js',
// 图片、字体等通过type:asset处理支援命名方式
assetModuleFilename: '/static/media/[hash:10][ext][query]',
// 自动清空上次打包结果
clean: true
},
// 加载器
module:{
// loader的配置
rules:[
{
// 每个文件只能被其中一个loader配置处理
oneOf: [
{
test: /\.css$/, // 检测.css文件
// 执行顺序,从左到右,从下到上
use: cssCommonloader()
},
{
test: /\.s[ac]ss$/, // 检测.sass 或 .scss文件
// sass-loader 将sass编译成css
use: cssCommonloader("sass-loader")
},
{
test: /\.styl$/, // 检测.styl文件
// 将stylus编译成css
use: cssCommonloader("stylus-loader")
},
{
test: /\.(png|jpe?g|gif|webp|svg)$/,
type: "asset",
parser: {
dataUrlCondition: {
// 小于10kb的图片转base64
maxSize: 10 * 1024, // 10kb
}
},
generator: {
// 指定图片名称和位置 [hash:10]名称hash值取前10位
filename: "static/images/[hash:10][ext][query]"
}
},
{
// 处理图标配置以及其他资源
test: /\.(eot|svg|ttf|woff|woff2|map3|avi|map4)$/,
type: 'asset/resource', // 当做静态资源直接复制文件
generator: {
filename: 'static/font/[hash:10][ext][query]' // 放到dist/font文件夹, 文件名格式如左
}
},
{
test: /\.?js$/,
// exclude: /node_modules/, // 排除node_modules中的js文件
include: path.resolve(__dirname, '../src'), // 只处理src下的文件,其它的不用处理
use: [
{
// 开启多进程
loader: "thread-loader",
options: {
works: threads // 进程数量
}
},
{
// 只能添加一个loader, use可以添加多个
loader: 'babel-loader',
options: {
// 开启Bable缓存
cacheDirectory: true,
// 关闭缓存的压缩
cacheCompression: false,
plugins: ["@babel/plugin-transform-runtime"] // 减少代码体积
}
}
]
}
]
}
],
},
// plugins配置
plugins:[
new ESLintPlugin({
// 检查src下面的文件
context: path.resolve(__dirname, "../src"),
exclude: "node_modules", // 默认值
cache: true, // 开启缓存
cacheLocation: path.resolve(__dirname, '../node_modules/.cache/eslintcache'), // 缓存的路径
threads, // 开启多进程和设置进程数量
}),
new HtmlWebpackPlugin({
// 模板:以 public/index.html 文件创建新的html文件
// 新的html文件特点:1. 结构和原来的一致 2. 自动引入打包生成的资源
template: path.resolve(__dirname, "../public/index.html")
}),
new MiniCssExtractPlugin({
// 修改文件输出地址
filename: 'static/css/main.css'
}),
new WorkboxPlugin.GenerateSW({
// 这些选项帮助快速启用 ServiceWorkers
// 不允许遗留任何旧的 ServiceWorkers
clientsClaim: true,
skipWaiting: true,
}),
// new CssMinimizerPlugin(),
// new TerserWebpackPlugin({
// parallel: threads // 开启多进程和设置进程数量
// })
],
// 压缩也可以在这里用, 功能一样
optimization: {
// 压缩的操作
minimizer: [
new CssMinimizerPlugin(),
new TerserWebpackPlugin({
parallel: threads // 开启多进程和设置进程数量
}),
// 图片压缩
new ImageMinimizerPlugin({
minimizer: {
implementation: ImageMinimizerPlugin.imageminMinify,
options: {
// Lossless optimization with custom option
// Feel free to experiment with options for better result for you
plugins: [
["gifsicle", { interlaced: true }],
["jpegtran", { progressive: true }],
["optipng", { optimizationLevel: 5 }],
// Svgo configuration here https://github.com/svg/svgo#configuration
[
"svgo",
{
plugins: [
{
name: "preset-default",
params: {
overrides: {
removeViewBox: false,
addAttributesToSVGElement: {
params: {
attributes: [
{ xmlns: "http://www.w3.org/2000/svg" },
],
},
},
},
},
},
],
},
],
],
},
},
}),
],
// js文件分割打包
splitChunks: {
// 打包生成的就是chunks
chunks: 'all', // 对所有模块镜像分割
// 下面的都是默认值
// minSize: 20000, // 分割的代码最小的大小
// minRemainingSize: 0, // 确保提取的文件大小不能为0
// minChunks: 1, // 至少被引入的次数,满足条件才经行分割
// maxAsyncRequests: 30, // 按需加载时并行加载的文件最大数量
// maxInitialRequests: 30, // 入口js文件最大并行请求数量
// enforceSizeThreshold: 50000, // 超过50kb一定会单独打包 (此时会忽略 minRemainingSize、maxAsyncRequests、maxInitialRequests)
// // 哪些模块要打包到一个组
// cacheGroups: {
// defaultVendors: { // 组名
// test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模块
// priority: -10, // 权重(越大越高)
// reuseExistingChunk: true, // 如果chunk包含已从 bundle 中拆分出来的模块,将会重用,不会生成新的模块
// },
// default: {
// minChunks: 2, // 权重更大, 会覆盖上面的 minChunks
// priority: -20,
// reuseExistingChunk: true,
// },
// },
},
},
// 模式
mode: "production",
devtool: "source-map"
}