一. WebPack
1.1. webpack简介
webpack 是一种前端资源构建工具,一个静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会在内部构建一个 依赖图(dependency graph),此依赖图对应映射到项目所需的每个模块,并生成一个或多个 bundle。
知识点:
1.2. webpack 核心概念
1.21. Entry
入口(Entry)指示 webpack 以哪个文件为入口起点开始打包,分析构建内部依赖图。
1.22. Output
输出(Output)指示 webpack 打包后的资源 bundles 输出到哪里去,以及如何命名。
1.23. Loader
Loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 能处理 js/json 资源)
1.24. Plugins
插件(Plugins)可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,
一直到重新定义环境中的变量等。
1.25. Mode
模式(Mode)指示 webpack 使用相应模式的配置
| 选项 | 描述 | 特点 |
|---|---|---|
| development | 会将 DefinePlugin 中的process.env.NODE_ENV值设为development | 开发环境(能让代码本地调试 ) |
| production | 默认值,会将 DefinePlugin 中的process.env.NODE_ENV值设为production | 生产环境(能让代码优化上线运行的环境 ) |
| none | 不使用任何默认优化选项 |
1.26. 浏览器兼容性
webpack 支持所有符合 ES5 标准 的浏览器(不支持 IE8 及以下版本)。webpack 的 import() 和 require.ensure() 需要 Promise。如果你想要支持旧版本浏览器,在使用这些表达式之前,还需要 提前加载 polyfill。
1.27. 环境
webpack 5 运行于 Node.js v10.13.0+ 的版本。
1.3. 初始化配置
-
初始化 package.json
输入指令: npm init -
下载并安装 webpack
输入指令: npm install webpack webpack-cli -g npm install webpack webpack-cli -D
1.4. 编译打包应用
-
创建文件
-
运行指令
-
开发环境指令:
webpack src/js/index.js -o build/js/built.js --mode=development功能:webpack 能够编译打包 js 和 json 文件,并且能将 es6 的模块化语法转换成 浏览器能识别的语法。
-
生产环境指令:
webpack src/js/index.js -o build/js/built.js --mode=production功能:在开发配置功能上多一个功能,压缩代码。
-
-
webpack 能够编译打包 js 和 json 文件。 能将 es6 的模块化语法转换成浏览器能识别的语法。 能压缩代码。
-
webpack 不能编译打包 css、img 等文件。 不能将 js 的 es6 基本语法转化为 es5 以下语法。
1.5. webpack 开发环境的基本配置
1.51. 配置文件 webpack.config.js
运行指令: webpack
// loader 下载 配置
// plugins 下载 引入 配置
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
// webpack配置
// 入口
entry: "./src/index.js",
// 出口
output: {
// 输出文件名
filename: "built.js",
// 输出路径
// __dirname 代表当前文件目录绝对路径
path: resolve(__dirname, "build"),
},
// loader配置
module: {
rules: [
// 匹配哪些文件
{
test: "/.css$/",
// 使用哪些loader进行处理
// style-loader 创建style标签,将js中的样式资源插入进行,添加到head中生效
// css-loader 将css文件变成commonjs模块加载js中,里面内容是样式字符串
// 执行顺序 从右向左
use: ["style-loader", "css-loader"],
},
// 详细loader配置
],
},
// plugins 的配置
plugins: [
new HtmlWebpackPlugin({
// 复制 './src/index.html' 文件,并自动引入打包输出的所有资源(JS/CSS)
template: "./src/index.html",
}),
],
// 模式
// 开发模式
// 生产环境 production
mode: "development",
};
1.52. 打包样式资源
1. 下载安装 loader 包 npm i css-loader style-loader less-loader less -D
2. 修改配置文件
module: {
rules: [
// 匹配哪些文件
{
test: "/.css$/",
use: ["style-loader", "css-loader"],
},
{
test: "/.less$/",
use: ["style-loader", "css-loader","less-loader"],
}
],
},
1.53. 打包HTML资源
1. 下载安装 plugin 包 npm install --save-dev html-webpack-plugin
2. 修改配置文件
const HtmlWebpackPlugin = require('html-webpack-plugin');
{
plugins: [
new HtmlWebpackPlugin({
// 复制 './src/index.html' 文件,并自动引入打包输出的所有资源(JS/CSS)
template: "./src/index.html",
}),
],
}
1.54. 打包图片资源
1. 下载安装 loader 包 npm install --save-dev html-loader url-loader file-loader
// 问题:默认处理不了 html 中 img 图片
// 处理图片资源
test: /\.(jpg|png|gif)$/,
// 使用一个 loader
// 下载 url-loader file-loader
loader: 'url-loader',
options: {
// 图片大小小于 8kb,就会被 base64 处理
// 优点: 减少请求数量(减轻服务器压力)
// 缺点:图片体积会更大(文件请求速度更慢)
limit: 8 * 1024,
// 问题:因为 url-loader 默认使用 es6 模块化解析,而 html-loader 引入图片是 commonjs
// 解析时会出问题:[object Module]
// 解决:关闭 url-loader 的 es6 模块化,使用 commonjs 解析
esModule: false,
// 给图片进行重命名
// [hash:10]取图片的 hash 的前 10 位
// [ext]取文件原来扩展名
name: '[hash:10].[ext]'
},
{
test: /\.html$/,
// 处理 html 文件的 img 图片(负责引入 img,从而能被 url-loader 进行处理)
loader: 'html-loader'
}
1.55. 打包其它资源
// 打包其他资源(除了 html/js/css 资源以外的资源)
{
// 排除 css/js/html 资源
exclude: /\.(css|js|html|less)$/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]'
}
}
1.56. devserver 自动化
const { resolve } = require("path");
module.export = {
entry: '',
output: {},
...
// 安装 npm webpack-dev-server -g
// 开发服务器 devServer :自动化编译,自动打开浏览器,自动刷新浏览器
// 特点: 只会在内存中编译打包,不会有任何输出
// 启动 devServer指令:npx webpack-dev-server
devServer: {
// 项目路径
contentBase: resolve(__dirname, 'build'),
// 启动gzip压缩
compress: true,
// 端口号
port: 3000,
// 自动打开浏览器
open: true
}
}
1.6. webpack 生产环境的基本配置
1.61. 提取 css 成单独文件
// 下载插件 npm install --save-dev mini-css-extract-plugin
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module: {
rules: [
{
test: /\.css$/,
use: [
// 创建 style 标签,将样式放入
// 'style-loader',
// 这个 loader 取代 style-loader。作用:提取js中的css成单独文件
MiniCssExtractPlugin.loader,
// 将 css 文件整合到 js 文件中
'css-loader',
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
// 对输出的 css 文件进行重命名
filename: 'css/built.css'
})
],
mode: 'development'
1.62. css 兼容性处理
// 安装 npm install --save-dev mini-css-extract-plugin
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 设置node.js 环境变量 决定使用browserlist的环境
process.env.NODE_ENV = development
module: {
rules: [
{
test: /\.css$/,
use: [
// 创建 style 标签,将样式放入
// 'style-loader',
// 这个 loader 取代 style-loader。作用:提取js中的css成单独文件
MiniCssExtractPlugin.loader,
// 将 css 文件整合到 js 文件中
'css-loader',
/*
css兼容性处理:postcss --> postcss-loader postcss-preset-env
通过package.json中的 browserlist里面的配置,来配置css兼容性样式
browserlist: {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production": [
">0.2%",
"not dead",
"not op_mini all"
]
}
*/
{
loader: 'postcss-loader',
options: {
ident:'postcss',
plugins: () => [
require('postcss-preset-env')()
]
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
// 对输出的 css 文件进行重命名
filename: 'css/built.css'
})
],
mode: 'development'
1.63. 压缩 css
// 下载插件 npm install --save-dev optimize-css-assets-webpack-plugin
const optimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
plugins: [
new optimizeCssAssetsWebpackPlugin()
],
1.64. js 语法检查 eslint
/*
安装: npm install --save-dev eslint-loader eslint eslint-config-airbnb-base eslint-plugin-import
语法检查: eslint-loader eslint
注意:只检查自己写的源代码,第三方的库是不用检查的
设置检查规则:
package.json 中 eslintConfig 中设置~
"eslintConfig": {
"extends": "airbnb-base",
"env": {
"browser": true
}
}
airbnb --> eslint-config-airbnb-base eslint-plugin-import eslint
*/
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'eslint-loader',
options: {
// 自动修复 eslint 的错误
fix: true
}
}
1.65. js 兼容性处理
/*
npm install --save-dev babel-loader @babel/core @babel/preset-env @babel/polyfill core-js
*/
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: { // 预设:指示 babel 做怎么样的兼容性处理
presets: [
[ '@babel/preset-env',
{
// 按需加载
useBuiltIns: 'usage',
// 指定 core-js 版本
corejs: {
version: 3
},
// 指定兼容性做到哪个版本浏览器
targets: {
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]
]
}
}
1.66. js 压缩
// 生产环境下会自动压缩 js 代码
mode: 'production'
1.67. HTML压缩
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
// 压缩 html 代码
minify: {
// 移除空格
collapseWhitespace: true,
// 移除注释
removeComments: true
}
})
],
二. WebPack 优化配置
2.1. HMR
HMR: hot module replacement 模块热替换
作用:一个模块发生变化,只会重新打包这一个模块,极大提升构建速度
devServer: {
contentBase: resolve(__dirname, 'build'),
compress: true,
port: 3000,
open: true,
// 开启 HMR 功能
// 当修改了 webpack 配置,新配置要想生效,必须重新 webpack 服务
hot: true
}
2.2. source-map
一种提供源代码到构建后代码映射技术(如果构建后代码出错,通过映射可以追踪源代码错误)
devtool: 'inline-source-map|hidden-source-map|eval-source-map|nosources-source-map|cheap-source-map|cheap-module-source-map'
开发环境 eval-source-map
生产环境 source-map
2.3. oneOf
只会匹配一个 loader
// 以下 loader 只会匹配一个
// 注意:不能有两个配置处理同一种类型文件
oneOf: [
{
test: /\.css$/,
use: [...commonCssLoader]
},
{
test: /\.less$/,
use: [...commonCssLoader, 'less-loader']
},
2.4. 缓存
// 开启 babel 缓存
// 第二次构建时,会读取之前的缓存
cacheDirectory: true
2.5. tree shaking
去除无用代码
- 前提:1. 必须使用ES6模块化 2. 开启production环境
- 作用:减少代码体积
2.6. code split
代码分割
// 单入口
// entry: './src/js/index.js',
entry: {
// 多入口:有一个入口,最终输出就有一个 bundle
index: './src/js/index.js',
test: './src/js/test.js' },
output: {
// [name]:取文件名
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, 'build')
},
/*
1. 可以将 node_modules 中代码单独打包一个 chunk 最终输出
2. 自动分析多入口 chunk 中,有没有公共的文件。如果有会打包成单独一个 chunk
*/
optimization: {
splitChunks: {
chunks: 'all'
}
},
2.7. 懒加载和预加载(lazy loading 和 prefetch)
2.8. PWA
渐进式网络开发应用程序(离线可访问)
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
plugin: [
new WorkboxWebpackPlugin.GenerateSW({
/*
1. 帮助 serviceworker 快速启动
2. 删除旧的 serviceworker
3. 生成一个 serviceworker 配置文件~
*/
clientsClaim: true, skipWaiting: true })
]
2.9. 多进程打包
// npm install --save-dev thread-loader
{
test: /\.js$/,
exclude: /node_modules/,
use: [
loader: 'thread-loader',
options: {
workers: 2 // 进程 2 个
}]
}
2.10. externals
externals: {
// 拒绝 jQuery 被打包进来
// 忽略库名 -- npm包名
jquery: 'jQuery'
}
2.11. dll
对某些库(第三方库:jquery,react,vue)进行单独打包
三. webpack详细配置
3.1. resolve
配置路径别名
resolve: {
// 配置解析模块路径别名: 优点简写路径 缺点路径没有提示
alias: {
$css: resolve(__dirname, 'src/css')
},
// 配置省略文件路径的后缀名
extensions: ['.js', '.json', '.jsx', '.css'],
// 告诉 webpack 解析模块是去找哪个目录
modules: [resolve(__dirname, '../../node_modules'),'node_modules']
}
3.2. optimization
module.exports = {
//...
optimization: {
splitChunks: {
chunks: 'async',
minSize: 20000,
minRemainingSize: 0,
minChunks: 1,
maxAsyncRequests: 30,
maxInitialRequests: 30,
enforceSizeThreshold: 50000,
cacheGroups: {
defaultVendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
reuseExistingChunk: true,
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
},
},
},
};
/* ------------------------------------------- */
optimization: {
splitChunks: {
chunks: 'all'
// 默认值,可以不写~
},
// 将当前模块的记录其他模块的 hash 单独打包为一个文件 runtime
// 解决:修改 a 文件导致 b 文件的 contenthash 变化
runtimeChunk: {
name: entrypoint => `runtime-${entrypoint.name}`
},
minimizer: [
// 配置生产环境的压缩方案:js 和 css
new TerserWebpackPlugin({
// 开启缓存
cache: true,
// 开启多进程打包
parallel: true,
// 启动 source-map
sourceMap: true
})
]
}
四. WebPack5
此版本重点关注以下内容:
- 通过持久缓存提高构建性能.
- 使用更好的算法和默认值来改善长期缓存.
- 通过更好的树摇和代码生成来改善捆绑包大小.
- 清除处于怪异状态的内部结构,同时在 v4 中实现功能而不引入任何重大更改.
- 通过引入重大更改来为将来的功能做准备,以使我们能够尽可能长时间地使用 v5.
4.1. Chunk 和模块 ID
添加了用于长期缓存的新算法。在生产模式下默认情况下启用这些功能。
chunkIds: "deterministic", moduleIds: "deterministic", mangleExports: "deterministic"
4.2. Chunk ID
在开发模式下,默认启用的新命名代码块 ID 算法为模块(和文件名)提供了人类可读的名称。 模块 ID 由其路径决定,相对于 context。 代码块 ID 由代码块的内容决定。
所以你不再需要使用import(/* webpackChunkName: "name" */ "module")来调试。 但如果你想控制生产环境的文件名,还是有意义的。
可以在生产环境中使用 chunkIds: "named" 在生产环境中使用,但要确保不要不小心暴露模块名的敏感信息。
迁移:如果你不喜欢在开发中改变文件名,你可以通过 chunkIds: "natural" 来使用旧的数字模式。
4.3. Tree Shaking
- webpack 现在能够处理对嵌套模块的 tree shaking
// inner.js
export const a = 1;
export const b = 2;
// module.js
import * as inner from './inner';
export { inner };
// user.js
import * as module from './module';
console.log(module.inner.a);
在生产环境中, inner 模块暴露的 b 会被删除
- webpack 现在能够多个模块之前的关系
import { something } from './something';
function usingSomething() {
return something;
}
export function test() {
return usingSomething();
}
当设置了"sideEffects": false时,一旦发现test方法没有使用,不但删除test,还会删除"./something"
- webpack 现在能处理对 Commonjs 的 tree shaking
4.4. Output
webpack 4 默认只能输出 ES5 代码
webpack 5 开始新增一个属性 output.ecmaVersion, 可以生成 ES5 和 ES6 / ES2015 代码.
如:output.ecmaVersion: 2015
4.5. SplitChunk
// webpack4
minSize: 30000;
// webpack5
minSize: {
javascript: 30000,
style: 50000,
}
4.6. Caching
// 配置缓存
cache: {
// 磁盘存储
type: "filesystem",
buildDependencies: {
// 当配置修改时,缓存失效
config: [__filename]
}
}
缓存将存储到 node_modules/.cache/webpack
4.7. 监视输出文件
之前 webpack 总是在第一次构建时输出全部文件,但是监视重新构建时会只更新修改的文件。
此次更新在第一次构建时会找到输出文件看是否有变化,从而决定要不要输出全部文件。
4.8. 默认值
entry: "./src/index.jsoutput.path: path.resolve(__dirname, "dist")output.filename: "[name].js"