webpack简介
BiliBili 视频地址: 尚硅谷2020最新版Webpack5实战教程
环境参数(本机)
Nodejs v14.15.0
webpack: "^5.11.0",
webpack-cli: "^4.2.0",
webpack-dev-server: "^3.11.0"
webpack
webpack 是一种前端资源构建工具,一个静态模块打包器(module bundler)。 在webpack 看来, 前端的所有资源文件(js/json/css/img/less/...)都会作为模块处理。 它将根据模块的依赖关系进行静态分析,打包生成对应的静态资源(bundle)。
webpack 五个核心概念
| 名称 | 描述 |
|---|---|
| Entry | 入口 |
| Output | 出口 |
| Loader | 转换 |
| Plugins | 插件 |
| Mode | 模式 |
-
Entry 入口(Entry)指示webpack 以哪个文件为入口起点开始打包,分析构建内部依赖图。
-
Output 输出(Output)指示webpack 打包后的资源bundles 输出到哪里去,以及如何命名。
-
Loader Loader 让webpack 能够去处理那些非JavaScript 文件(webpack 自身只理解JavaScript)
-
Plugins 插件(Plugins)可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩, 一直到重新定义环境中的变量等。
-
Mode 模式(Mode)指示webpack 使用相应模式的配置。
选项 描述 特点 development 会将DefinePlugin 中process.env.NODE_ENV 的值设置
为development。启用NamedChunksPlugin 和
NamedModulesPlugin。能让代码本地调试
运行的环境production 会将DefinePlugin 中process.env.NODE_ENV 的值设置
为production。启用FlagDependencyUsagePlugin,
FlagIncludedChunksPlugin, ModuleConcatenationPlugin,
NoEmitOnErrorsPlugin, OccurrenceOrderPlugin,
SideEffectsFlagPlugin 和TerserPlugin。能让代码优化上线
运行的环境
压缩(常用)--- 一般都是用插件
兼容性处理---- 一般都是用各种loader处理
package.json配置
postcss高版本有错误, 稳定3.0.0可以使用
//package.json配置
{
"name": "webpack_code",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.12.10",
"@babel/polyfill": "^7.12.1",
"@babel/preset-env": "^7.12.11",
"add-asset-html-webpack-plugin": "^3.1.3",
"babel": "^6.23.0",
"babel-loader": "^8.2.2",
"core-js": "^3.8.1",
"css-loader": "^5.0.1",
"eslint": "^7.16.0",
"eslint-config-airbnb-base": "^14.2.1",
"eslint-loader": "^4.0.2",
"eslint-plugin-import": "^2.22.1",
"file-loader": "^6.2.0",
"html-loader": "^1.3.2",
"html-webpack-plugin": "^4.5.0",
"less": "^4.0.0",
"less-loader": "^7.1.0",
"mini-css-extract-plugin": "^1.3.3",
"optimize-css-assets-webpack-plugin": "^5.0.4",
"postcss-loader": "^3.0.0",
"postcss-preset-env": "^6.7.0",
"style-loader": "^2.0.0",
"terser-webpack-plugin": "^5.0.3",
"thread-loader": "^3.0.1",
"url-loader": "^4.1.1",
"webpack": "^5.11.0",
"webpack-cli": "^4.2.0",
"webpack-dev-server": "^3.11.0",
"workbox-webpack-plugin": "^6.0.2"
},
"dependencies": {
"jquery": "^3.5.1"
},
"browserslist": {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production": [
">0.2%",
"not dead",
"not op_mini all"
]
},
"eslintConfig": {
"extends": "airbnb-base",
"env": {
"browser": true
}
},
"sideEffects": [
"*.css"
]
}
webpack配置规则
1.entry配置
入口起点
-
string
'./src/index.js'----------使用最多- 单入口
- 打包形成一个chunk ,输出一个bundle文件
- 此时chunk的名称默认是main
-
array
['./src/index.js', './src/add.js']------------使用较多- 多入口
- 所有入口文件最终形成一个chunk ,输出一个bundle文件,默认也叫main
- 作用只有在HMR功能中让html热更新生效
-
object
{index: './src/index.js',add: './src/add.js'}- 多入口(名称: 路径)
- 有几个入口就有几个chunk,输出几个bundle文件
- chunk的名称是key
-
特殊用法(复用性)
{ index: ['./src/index.js', './src/add.js'], count: './src/count.js' }
多入口打包 示例:
//多入口。 多出口 打包
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
index: ['./src/index.js', './src/count.js'], //index文件中有两个js文件内容
add: './src/add.js' //生成的add文件中只有add.js内容
},
output: {
filename: '[name].js',
path: resolve(__dirname, 'build')
},
plugins: [new HtmlWebpackPlugin()],
mode: 'development'
};
2.output配置
output: {
// 文件名
filename: '[name].js',
// 文件构建的路径
path: resolve(__dirname, 'build'),
// 所有输出资源的公共路径前缀, '/'一般用于生产环境
publicPath: './',
// 非入口chunk 的名称,由于有多个chunk,可以重命名
chunkFilename: 'js/[name]_chunk.js',
// 整个库向外暴露的变量名
library: '[name]',
// 变量名添加到哪个上 window,global,commonjs
// library: '[name]', // 整个库向外暴露的变量名
// libraryTarget: 'window' // 变量名添加到哪个上 browser
// libraryTarget: 'global' // 变量名添加到哪个上 node
// libraryTarget: 'commonjs'
}
示例
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
// 文件名称(指定名称+目录)
filename: 'js/[name].js',
// 输出文件目录(将来所有资源输出的公共目录)
path: resolve(__dirname, 'build'),
// 所有资源引入公共路径前缀 --> 'imgs/a.jpg' --> '/imgs/a.jpg'
publicPath: '/',
chunkFilename: 'js/[name]_chunk.js', // 非入口chunk的名称
// library: '[name]', // 整个库向外暴露的变量名
// libraryTarget: 'window' // 变量名添加到哪个上 browser
// libraryTarget: 'global' // 变量名添加到哪个上 node
// libraryTarget: 'commonjs'
},
plugins: [new HtmlWebpackPlugin()],
mode: 'development'
};
3.module配置
常见配置规则:
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'js/[name].js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
// loader的配置
{
test: /\.css$/,
// 多个loader用use
// loader: 'style-loader' //单个loader使用
use: ['style-loader', 'css-loader']
},
{
test: /\.js$/,
// 排除node_modules下的js文件
exclude: /node_modules/,
// 只检查 src 下的js文件
include: resolve(__dirname, 'src'),
// 优先执行
enforce: 'pre',
// 延后执行
// enforce: 'post',
// 单个loader用loader
loader: 'eslint-loader',
options: {}
},
{
// 以下配置只会生效一个
oneOf: []
}
]
},
plugins: [new HtmlWebpackPlugin()],
mode: 'development'
};
4.resolve配置
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/[name].js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
},
plugins: [new HtmlWebpackPlugin()],
mode: 'development',
// 解析模块的规则
resolve: {
// 配置解析模块路径别名: 优点简写路径 缺点路径没有提示
alias: {
$css: resolve(__dirname, 'src/css')
},
// 配置省略文件路径的后缀名,默认是.js, 引入的时候可以简写, 例如 import main from 'home',相当于home/index.js
extensions: ['.js', '.json', '.jsx', '.css'],
// 告诉 webpack 解析模块是去找哪个目录
modules: [resolve(__dirname, '../../node_modules'), 'node_modules']//第一个是相对路径,第二个是防止前一个失效
}
};
5.devServer配置
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/[name].js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
},
plugins: [new HtmlWebpackPlugin()],
mode: 'development',
resolve: {
alias: {
$css: resolve(__dirname, 'src/css')
},
extensions: ['.js', '.json', '.jsx', '.css'],
modules: [resolve(__dirname, '../../node_modules'), 'node_modules']
},
devServer: {
// 运行代码的目录
contentBase: resolve(__dirname, 'build'),
// 监视 contentBase 目录下的所有文件,一旦文件变化就会 reload
watchContentBase: true,
watchOptions: {
// 忽略文件
ignored: /node_modules/
},
// 启动gzip压缩
compress: true,
// 端口号
port: 3000,
// 域名
host: 'localhost',
// 自动打开浏览器
open: true,
// 开启HMR功能
hot: true,
// 不要显示启动服务器日志信息
clientLogLevel: 'none',
// 除了一些基本启动信息以外,其他内容都不要显示
quiet: true,
// 如果出错了,不要全屏提示
overlay: false,
// 服务器代理 --> 解决开发环境跨域问题
proxy: {
// 一旦devServer(5000)服务器接受到 /api/xxx 的请求,就会把请求转发到另外一个服务器(3000)
'/api': {
target: 'http://localhost:3000',
// 发送请求时,请求路径重写:将 /api/xxx --> /xxx (去掉/api)
pathRewrite: {
'^/api': ''
}
}
}
}
};
6.Optimization配置
关于Chunk的配置 和修改压缩的配置
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const TerserWebpackPlugin = require('terser-webpack-plugin')
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, 'build'),
chunkFilename: 'js/[name].[contenthash:10]_chunk.js'
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
},
plugins: [new HtmlWebpackPlugin()],
mode: 'production',
resolve: {
alias: {
$css: resolve(__dirname, 'src/css')
},
extensions: ['.js', '.json', '.jsx', '.css'],
modules: [resolve(__dirname, '../../node_modules'), 'node_modules']
},
optimization: {
splitChunks: {
chunks: 'all' //一般只要设置为all即可
// 默认值,可以不写~
/* minSize: 30 * 1024, // 分割的chunk最小为30kb
maxSize: 0, // 最大没有限制
minChunks: 1, // 要提取的chunk最少被引用1次
maxAsyncRequests: 5, // 按需加载时并行加载的文件的最大数量
maxInitialRequests: 3, // 入口js文件最大并行请求数量
automaticNameDelimiter: '~', // 名称连接符
name: true, // 可以使用命名规则
cacheGroups: {
// 分割chunk的组
// node_modules文件会被打包到 vendors 组的chunk中。--> vendors~xxx.js
// 满足上面的公共规则,如:大小超过30kb,至少被引用一次。
vendors: {
test: /[\\/]node_modules[\\/]/,
// 优先级
priority: -10
},
default: {
// 要提取的chunk最少被引用2次
minChunks: 2,
// 优先级
priority: -20,
// 如果当前要打包的模块,和之前已经被提取的模块是同一个,就会复用,而不是重新打包模块
reuseExistingChunk: true
}
}
*/
},
// 将当前模块的记录其他模块的hash单独打包为一个文件 runtime
// 解决:修改a文件导致b文件的contenthash变化
//重要!!
runtimeChunk: {
name: entrypoint => `runtime-${entrypoint.name}`
},
minimizer: [
// 配置生产环境的压缩方案:js和css
//注册一下
new TerserWebpackPlugin({
// 开启缓存
cache: true,
// 开启多进程打包
parallel: true,
// 启动source-map
sourceMap: true
})
]
}
};
webPack开发环境配置 dev
1.webpack初体验
安装
npm i webpack webpack-cli -D
使用
#开发模式
webpack ./src/index.js -o ./build/built.js --mode=development
#生成模式
webpack ./src/index.js -o ./build/built.js --mode=production
未配置前,只能处理js/json文件,不能处理css/img等其他资源
配置模板
// file:webpack.config.js webpack的配置文件
const {resolve} = require('path')
module.exports = {
// 入口起点
entry: './src/index.js',
// 出口
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
// loader的配置
module: {
rules: [
// 详细loader配置
]
},
// plugins的配置
plugins: [
],
// 模式
mode: 'development' //开发模式
// mode: 'production' //生产模式
}
2.打包CSS样式资源
安装
npm i style-loader css-loader -D
npm i less-loader -D
配置
use数组中loader执行顺序:从右到左,从下到上 依次执行
/*
webpack.config.js webpack的配置文件
作用: 指示 webpack 干哪些活(当你运行 webpack 指令时,会加载里面的配置)
所有构建工具都是基于nodejs平台运行的~模块化默认采用commonjs。
*/
// resolve用来拼接绝对路径的方法
const { resolve } = require('path');
module.exports = {
// webpack配置
// 入口起点
entry: './src/index.js',
// 输出
output: {
// 输出文件名
filename: 'built.js',
// 输出路径
// __dirname nodejs的变量,代表当前文件的目录绝对路径
path: resolve(__dirname, 'build')
},
// loader的配置
module: {
rules: [
// 详细loader配置
// 不同文件必须配置不同loader处理
{
// 匹配哪些文件
test: /\.css$/,
// 使用哪些loader进行处理
use: [
// use数组中loader执行顺序:从右到左,从下到上 依次执行
// 创建style标签,将js中的样式资源插入进行,添加到head中生效
'style-loader',
// 将css文件变成commonjs模块加载js中,里面内容是样式字符串
'css-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
// 将less文件编译成css文件
// 需要下载 less-loader和less
'less-loader'
]
}
]
},
// plugins的配置
plugins: [
// 详细plugins的配置
],
// 模式
mode: 'development', // 开发模式
// mode: 'production'
}
打包
webpack
运行
webpack serve
3. 打包html资源
安装
npm i html-webpack-plugin -D
引入
// file:webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
使用
/*
loader: 1. 下载 2. 使用(配置loader)
plugins: 1. 下载 2. 引入 3. 使用
*/
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
publicPath: '',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
// loader的配置
]
},
plugins: [
// plugins的配置
// html-webpack-plugin
// 功能:默认会创建一个空的HTML,自动引入打包输出的所有资源(JS/CSS)
// 需求:需要有结构的HTML文件
new HtmlWebpackPlugin({
// 复制 './src/index.html' 文件,并自动引入打包输出的所有资源(JS/CSS)
template: './src/index.html'
})
],
mode: 'development'
};
4.打包图片资源
安装
npm i url-loader file-loader html-loader -D
配置
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
publicPath: '',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.less$/,
// 要使用多个loader处理用use
use: ['style-loader', 'css-loader', 'less-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'
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development'
};
5.打包其他资源
file-loader 前面已经安装
配置
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
publicPath:'',
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
// 打包其他资源(除了html/js/css资源以外的资源)
{
// 排除css/js/html资源
exclude: /\.(css|js|html|less)$/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]'
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development'
};
6.devServer 热更新
作用
开发服务器,自动编译,自动刷新,自动打开浏览器
只会在内存中编译打包,不会有任何输出
安装
npm i webpack-dev-server -D
配置
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
publicPath:'',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
// 打包其他资源(除了html/js/css资源以外的资源)
{
// 排除css/js/html资源
exclude: /\.(css|js|html|less)$/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]'
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development',
// 开发服务器 devServer:用来自动化(自动编译,自动打开浏览器,自动刷新浏览器~~)
// 特点:只会在内存中编译打包,不会有任何输出
// 启动devServer指令为:webpack serve即可
+ devServer: {
// 项目构建后路径
+ contentBase: resolve(__dirname, 'build'),
// 启动gzip压缩
+ compress: true,
// 端口号
+ port: 3000,
// 自动打开浏览器
+ open: true
}
};
使用
webpack serve
7.开发环境配置汇总
./src/文件结构
│ index.html │ ├───css │ iconfont.css │ index.less │ ├───imgs │ angular.jpg │ react.png │ vue.jpg │ ├───js │ index.js │ └───media iconfont.eot iconfont.svg iconfont.ttf iconfont.woff
/*
开发环境配置:能让代码运行
运行项目指令:
webpack 会将打包结果输出出去
npx webpack-dev-server 只会在内存中编译打包,没有输出
*/
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
publicPath:'',
path: resolve(__dirname, 'build')
},
module: {
rules: [
// loader的配置
{
// 处理less资源
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
},
{
// 处理css资源
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
// 处理图片资源
test: /\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
// 关闭es6模块化
esModule: false,//否则url-loader会按照commonJS处理
outputPath: 'imgs'
}
},
{
// 处理html中img资源
test: /\.html$/,
loader: 'html-loader'
},
{
// 处理其他资源
exclude: /\.(html|js|css|less|jpg|png|gif)/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]',
outputPath: 'media'
}
}
]
},
plugins: [
// plugins的配置
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development',
devServer: {
contentBase: resolve(__dirname, 'build'),
compress: true,
port: 3000,
open: true,
hot:true //重要,只更新改变的文件
}
};
webPack生产环境配置 production
1.提取css成单独文件
生成单独的CSS文件, 而不是嵌入在js文件中。
mini-css-extract-plugin取代了style-loader。作用:提取js中的css成单独文件
安装
npm i mini-css-extract-plugin -D
引入
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
配置
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
+ const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
publicPath:'',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: [
// 创建style标签,将样式放入
// 'style-loader',
+ MiniCssExtractPlugin.loader, // 这个loader取代style-loader。作用:提取js中的css成单独文件
// 将css文件整合到js文件中
'css-loader'
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
+ new MiniCssExtractPlugin({
+ // 对输出的css文件进行重命名
+ filename: 'css/built.css'
})
],
mode: 'development'
};
2.css的兼容性处理
安装
npm i postcss-loader postcss-preset-env
配置
在package.json中
"browserslist": {
开发环境 --> 设置node环境变量:process.env.NODE_ENV = development
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
生产环境:默认是看生产环境
"production": [
">0.2%",
"not dead",
"not op_mini all"
]
}
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 设置nodejs环境变量---开发环境(必须单独注明,默认是生产环境)
process.env.NODE_ENV = 'development';
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
/*
css兼容性处理:postcss --> postcss-loader postcss-preset-env
帮postcss找到package.json中browserslist里面的配置,通过配置加载指定的css兼容性样式
*/
// 使用loader的默认配置
// 'postcss-loader',
// 修改loader的配置
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
// postcss的插件
require('postcss-preset-env')()
]
}
}
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new MiniCssExtractPlugin({
filename: 'css/built.css'
})
],
mode: 'development'
};
3.压缩css
安装
npm i optimize-css-assets-webpack-plugin -D
引入
const OptimizeCssAssetsWebpackPlugin= require('optimize-css-assets-webpack-plugin')
配置
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
// 设置nodejs环境变量
// process.env.NODE_ENV = 'development';
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
publicPath:'',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
// postcss的插件
require('postcss-preset-env')()
]
}
}
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new MiniCssExtractPlugin({
filename: 'css/built.css'
}),
// 压缩css
new OptimizeCssAssetsWebpackPlugin()
],
mode: 'development'
};
4.js语法检查
注:有很多可以用的风格,如:aribnb风格, 或js- standard-style风格
Package.json中进行配置
package.json中要进行配置
"eslintConfig": {
"extends": "airbnb-base",
"env": {
"browser": true
}
},
安装:
1.Airbnb风格
npm i
eslint-loader
eslint
eslint-config-airbnb-base
eslint-plugin-import
-D
2.Standard风格
npm install
eslint-loader
eslint
eslint-config-standard
eslint-plugin-standard
eslint-plugin-promise
eslint-plugin-import
eslint-plugin-node -D
配置
// file: package.json
"eslintConfig": {
"extends": "standard"
}
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
/*
语法检查: eslint-loader eslint
注意:只检查自己写的源代码,第三方的库是不用检查的
设置检查规则:
package.json中eslintConfig中设置~
"eslintConfig": {
"extends": "airbnb-base"
}
airbnb --> eslint-config-airbnb-base eslint-plugin-import eslint
*/
{
test: /\.js$/,
exclude: /node_modules/,
// 确保所有的eslint优先执行
enforce: 'pre',
loader: 'eslint-loader',
options: {
// 自动修复eslint的错误
fix: true
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development'
};
想让特殊行EsLint失效(下一行不进行eslint检查) -------使用较少
加eslint-disable-next-line
function add(x, y) {
return x + y;
}
// 下一行eslint所有规则都失效(下一行不进行eslint检查)
// eslint-disable-next-line
console.log(add(2, 5));
5.js兼容性处理
兼容处理有三种
@babel/preset-env 基本js兼容处理 问题:只能转换基本语法,如promise等高级语法,不能转换
@babel/polyfill 全部兼容处理
问题:会将所有的代码做兼容处理,但体积太大, 大约400k以上
core-js 按需加载,----推荐
安装
1.基本的语法降级
npm i babel-loader
@babel/core
@babel/preset-env -D
2.Promise, async等处理
npm i @babel/polyfill -D
//需要再使用的地方 做顶部引入 // import '@babel/polyfill';
3.结合基本babel, 使用Core.js 进行按需加载
npm i babel-loader
core-js
@babel/core
@babel/preset-env -D
配置
// 第一种 增加loader,即module中的rules
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
// 第二 直接在js文件中增加
import '@babel/polyfill'
// 第三种 增加loader,即module中的rules
{
test: /\.js$/,
exclude: /node_modules/,
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'
}
}]
]
}
}
6.js压缩
// file: webpack.config.js 只需要切换成生产模式即可
// 生产环境下会自动压缩js代码
mode: 'production'
7.html压缩
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
publicPath:'',
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
// 压缩html代码
minify: {
// 移除空格
collapseWhitespace: true,
// 移除注释
removeComments: true
}
})
],
mode: 'production'
};
8.生产环境配置汇总
const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 定义nodejs环境变量:决定使用browserslist的哪个环境
process.env.NODE_ENV = 'production';//development
// 复用loader
const commonCssLoader = [
MiniCssExtractPlugin.loader,
'css-loader',
{
// 还需要在package.json中定义browserslist
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [require('postcss-preset-env')()]
}
}
];
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: [...commonCssLoader]
},
{
test: /\.less$/,
use: [...commonCssLoader, 'less-loader']
},
/*
正常来讲,一个文件只能被一个loader处理。
当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:
先执行eslint 在执行babel
*/
{
// 在package.json中eslintConfig --> airbnb
test: /\.js$/,
exclude: /node_modules/,
// 确保所有的eslint优先执行
enforce: 'pre',
loader: 'eslint-loader',
options: {
fix: true
}
},
// 语法降级, 使用babel和core.js
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: {version: 3},
targets: {
chrome: '60',
firefox: '50'
}
}
]
]
}
},
{
test: /\.(jpg|png|gif)/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
outputPath: 'imgs',
esModule: false
}
},
{
test: /\.html$/,
loader: 'html-loader'
},
// 处理其他文件
{
exclude: /\.(js|css|less|html|jpg|png|gif)/,
loader: 'file-loader',
options: {
outputPath: 'media'
}
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/built.css'
}),
new OptimizeCssAssetsWebpackPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
mode: 'production'
};
重要! WebPack优化配置
1.简介
# webpack性能优化
* 开发环境性能优化
* 生产环境性能优化
## 开发环境性能优化
* 优化打包构建速度
* HMR
* 优化代码调试
* source-map
## 生产环境性能优化
* 优化打包构建速度
* oneOf
* babel缓存
* 多进程打包
* externals
* dll
* 优化代码运行的性能
* 缓存(hash-chunkhash-contenthash)
* tree shaking
* code split
* 懒加载/预加载
* pwa
2.HMR功能
HMR: hot module replacement 热模块替换,一个文件修改后,只重新构建该文件,而不是全部构建
提升构建速度
样式文件:可以使用HMR功能:因为style-loader内部实现了~
js文件:默认不能使用HMR功能 --> 需要修改js代码,添加支持HMR功能的代码
注意:HMR功能对js的处理,只能处理非入口js文件的其他文件。
html文件: 默认不能使用HMR功能.同时会导致问题:html文件不能热更新了 (不用做HMR功能,入口就一个)
解决:修改entry入口,将html文件引入
开启热功能
// file: webpack.config.js
devServer: {
contentBase: resolve(__dirname, 'build'),
compress: true,
port: 3000,
open: true,
// 开启HMR功能
hot: true
}
-
样式文件:默认有HMR功能,因为style-loader内部实现了
-
js文件:默认无HMR功能
// file:./src/js/index.js 入口js文件下方添加 //引入了./print.js if (module.hot) { // 一旦 module.hot 为true,说明开启了HMR功能。 --> 让HMR功能代码生效 module.hot.accept('./print.js', function() { // 方法会监听 print.js 文件的变化,一旦发生变化,其他模块不会重新打包构建。 // 会执行后面的回调函数 print(); }); } -
html文件:默认无HMR功能,而且会导致无法热更新
// file: webpack.config.js entry: ['./src/js/index.js', './src/index.html']
3. Source-map
找到源代码的错误信息和错误位置
source-map: 一种 提供源代码到构建后代码映射 技术 (如果构建后代码出错了,通过映射可以追踪源代码错误)
source-map:外部 提供 错误代码准确信息 和 源代码的错误位置
inline-source-map:内联 只生成一个内联source-map 提供错误代码准确信息 和 源代码的错误位置
hidden-source-map:外部 错误代码错误原因,但是没有错误位置 。 // 不能追踪源代码错误,只能提示到构建后代码的错误位置
eval-source-map:内联 每一个文件都生成对应的source-map,都在eval 提供错误代码准确信息 和 源代码的错误位置
nosources-source-map:外部 错误代码准确信息, 但是没有任何源代码信息
cheap-source-map:外部 提供 错误代码准确信息 和 源代码的错误位置 ,只能精确到行
cheap-module-source-map: 外部 提供 错误代码准确信息 和 源代码的错误位置
module会将loader的source map加入
内联 和 外部的区别:1. 外部生成了文件,内联没有 2. 内联构建速度更快
开发环境:速度快,调试更友好
速度快(eval>inline>cheap>...)
eval-cheap-souce-map
eval-source-map
调试更友好
souce-map
cheap-module-souce-map
cheap-souce-map
--> eval-source-map / eval-cheap-module-souce-map
生产环境:源代码要不要隐藏? 调试要不要更友好
内联会让代码体积变大,所以在生产环境不用内联
nosources-source-map 全部隐藏
hidden-source-map 只隐藏源代码,会提示构建后代码错误信息
--> source-map / cheap-module-souce-map
使用
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: ['./src/js/index.js', './src/index.html'],
output: {
filename: 'js/built.js',
publicPath:'',
path: resolve(__dirname, 'build')
},
module: {
rules: [
// loader的配置
{
// 处理less资源
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
},
{
// 处理css资源
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
// 处理图片资源
test: /\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
// 关闭es6模块化
esModule: false,
outputPath: 'imgs'
}
},
{
// 处理html中img资源
test: /\.html$/,
loader: 'html-loader'
},
{
// 处理其他资源
exclude: /\.(html|js|css|less|jpg|png|gif)/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]',
outputPath: 'media'
}
}
]
},
plugins: [
// plugins的配置
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development',
devServer: {
contentBase: resolve(__dirname, 'build'),
compress: true,
port: 3000,
open: true,
hot: true
},
devtool: 'eval-source-map'
};
参数
[inline-|hidden-eval-][nosourses-][cheap-[module-]]source-map
| 属性 | 存放位置 | 错误原因 | 错误位置 |
|---|---|---|---|
| source-map | 外部 | 源文件 | 源文件 |
| inline-source-map | 内联 | 源文件 | 源文件 |
| eval-source-map | 内联 | 源文件(+hash) | 源文件 |
| hidden-source-map | 外部 | 构建文件 | 构建文件 |
| nosources-source-map | 外部 | 源文件 | 无 |
| cheap-source-map | 外部 | 源文件 | 源文件(1行) |
| cheap-module-source-map | 外部 | 源文件 | 源文件(1行) |
开发环境推荐:eval-source-map 速度快(eval>inline>cheap>...)
生产环境推荐:source-map / cheap-source-map / hidden-source-map 都可以
4.oneOf
只匹配一个loader,例如CSS/LESS , 不用全部都匹配,优化打包构建速度
const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 定义nodejs环境变量:决定使用browserslist的哪个环境
process.env.NODE_ENV = 'production';
// 复用loader
const commonCssLoader = [
MiniCssExtractPlugin.loader,
'css-loader',
{
// 还需要在package.json中定义browserslist
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [require('postcss-preset-env')()]
}
}
];
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
// 在package.json中eslintConfig --> airbnb
test: /\.js$/,
exclude: /node_modules/,
// 优先执行
+ enforce: 'pre',
loader: 'eslint-loader',
options: {
fix: true
}
},
{
// 以下loader只会匹配一个
// 注意:不能有两个配置处理同一种类型文件
+ oneOf: [
+ {
+ test: /\.css$/,
+ use: [...commonCssLoader]
+ },
+ {
+ test: /\.less$/,
+ use: [...commonCssLoader, 'less-loader']
+ },
/*
正常来讲,一个文件只能被一个loader处理。
当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:
先执行eslint 在执行babel
*/
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: {version: 3},
targets: {
chrome: '60',
firefox: '50'
}
}
]
]
}
},
{
test: /\.(jpg|png|gif)/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
outputPath: 'imgs',
esModule: false
}
},
{
test: /\.html$/,
loader: 'html-loader'
},
{
exclude: /\.(js|css|less|html|jpg|png|gif)/,
loader: 'file-loader',
options: {
outputPath: 'media'
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/built.css'
}),
new OptimizeCssAssetsWebpackPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
mode: 'production'
};
5. Babel缓存
- babel缓存(第二次打包构建速度更快)
设置cacheDirectory: true开启哈希缓存,
使用contentHash 较好,, 推荐
// 修改js-loader中的options
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
// 开启babel缓存,第二次构建时读取缓存
cacheDirectory: true
}
}
-
加哈希值
- filename: 'js/built.[contenthash:10].js',
//加哈希值,确保文件更新后再次读取,如未变动,哈希值不会变,也就不会重新加载,直接读取缓存
- filename: 'css/built.[contenthash:10].css
babel缓存 cacheDirectory: true --> 让第二次打包构建速度更快 文件资源缓存 hash: 每次wepack构建时会生成一个唯一的hash值。 问题: 因为js和css同时使用一个hash值。 如果重新打包,会导致所有缓存失效。(可能我却只改动一个文件) chunkhash:根据chunk生成的hash值。如果打包来源于同一个chunk,那么hash值就一样 问题: js和css的hash值还是一样的 因为css是在js中被引入的,所以同属于一个chunk contenthash: 根据文件的内容生成hash值。不同文件hash值一定不一样 --> 让代码上线运行缓存更好使用
* 文件资源缓存(让上线运行缓存更好使用)
* hash 每次webpack会生成唯一的hash值,如果只改动一个文件,打包后会导致所有缓存失效
* chunkhash 如果打包来自同一个chunk,则hash值相同
* contenthash 根据内容生成hash值。
// 在生成的文件名中加上不同hash值
output: {
filename: 'js/built.[contenthash:10].js',
path: resolve(__dirname, 'build')
}
new MiniCssExtractPlugin({
filename: 'css/built.[contenthash:10].css'
})
完整代码
const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 定义nodejs环境变量:决定使用browserslist的哪个环境
process.env.NODE_ENV = 'production';
// 复用loader
const commonCssLoader = [
MiniCssExtractPlugin.loader,
'css-loader',
{
// 还需要在package.json中定义browserslist
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [require('postcss-preset-env')()]
}
}
];
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.[contenthash:10].js',
//加哈希值,确保文件更新后再次读取,如未变动,哈希值不会变,也就不会重新加载,直接读取缓存
publicPath:'',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
// 在package.json中eslintConfig --> airbnb
test: /\.js$/,
exclude: /node_modules/,
// 优先执行
enforce: 'pre',
loader: 'eslint-loader',
options: {
fix: true
}
},
{
// 以下loader只会匹配一个
// 注意:不能有两个配置处理同一种类型文件
oneOf: [
{
test: /\.css$/,
use: [...commonCssLoader]
},
{
test: /\.less$/,
use: [...commonCssLoader, 'less-loader']
},
/*
正常来讲,一个文件只能被一个loader处理。
当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:
先执行eslint 在执行babel
*/
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: { version: 3 },
targets: {
chrome: '60',
firefox: '50'
}
}
]
],
// 开启babel缓存
// 第二次构建时,会读取之前的缓存
cacheDirectory: true
}
},
{
test: /\.(jpg|png|gif)/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
outputPath: 'imgs',
esModule: false
}
},
{
test: /\.html$/,
loader: 'html-loader'
},
{
exclude: /\.(js|css|less|html|jpg|png|gif)/,
loader: 'file-loader',
options: {
outputPath: 'media'
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/built.[contenthash:10].css'
}),
new OptimizeCssAssetsWebpackPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
mode: 'production',
devtool: 'source-map'
};
6. Tree-shaking
可以用于 去除无用代码
前提:必须使用es6模块化import, module.export ,开启production环境
在Package.json中设置"sideEffects": false 所有代码都没有副作用(都可以进行tree shaking)
问题:可能会把css / @babel/polyfill (副作用)文件干掉
若要跳过css等其他文件, package.json中设置:
"sideEffects": ["*.css", "*.less"]
7. code split 代码分割
-
多入口---指定每一个入口,麻烦
const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { // 单入口 // 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') }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html', minify: { collapseWhitespace: true, removeComments: true } }) ], mode: 'production' }; -
optimization--- 进行代码分割
const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { // 单入口 // entry: './src/js/index.js', entry: { index: './src/js/index.js', test: './src/js/test.js' }, output: { // [name]:取文件名 filename: 'js/[name].[contenthash:10].js', path: resolve(__dirname, 'build') }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html', minify: { collapseWhitespace: true, removeComments: true } }) ], /* 1. 可以将node_modules中代码单独打包一个chunk最终输出 2. 自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk */ optimization: { splitChunks: { chunks: 'all' } }, mode: 'production' }; -
纯粹的单入口
-
通过js代码,让某个文件被单独打包成一个chunk , import动态导入语法:能将某个文件单独打包
如果希望固定每次打包后更新同一个chunks, 可以指定chunks iD,
import(/* webpackChunkName: 'test' */'./test')
.then(({ mul, count }) => {
// 文件加载成功~
// eslint-disable-next-line
console.log(mul(2, 5));
})
.catch(() => {
// eslint-disable-next-line
console.log('文件加载失败~');
});
8.Lazy Loading 懒加载
懒加载:文件需要使用时才加载
预加载(慎用): 会在使用之前空闲时提前加载js, 调用的时候直接读取缓存,速度快**,但兼容性差, IE/移动端 会需要大量调试**
懒加载:当文件需要使用时才加载~ 预加载 prefetch:会在使用之前,提前加载js文件 正常加载可以认为是并行加载(同一时间加载多个文件)
预加载 prefetch:等其他资源加载完毕,浏览器空闲了,再偷偷加载资源
- 在JS文件中加载
// file: ./src/js/index.js
document.getElementById('btn').onclick = function() {
import(/* webpackChunkName: 'test', webpackPrefetch: true */'./test').then(({ mul }) => {
console.log(mul(4, 5));//20
});
};
9.PWA技术
渐进式网络开发应用程序(离线可访问)
安装插件
npm i workbox-webpack-plugin -D
引入
const WorkboxWebpackPlugin = require('workbox-webpack-plugin')
配置
// file: webpack.config.js
plugins: [
new WorkboxWebpackPlugin.GenerateSW({
/*
1. 帮助serviceworker快速启动
2. 删除旧的 serviceworker
生成一个 serviceworker 配置文件~
*/
clientsClaim: true,
skipWaiting: true
})
],
使用,在index.js文件中设置
// file: ./src/js/index.js
// 注册serviceworker
// 处理兼容性问题
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker
.register('/service-worker.js')
.then(() => {
console.log('sw注册成功了');
})
.catch(() => {
console.log('sw注册失败了');
});
});
}
服务器搭建(serviceWorker只能在服务器中使用)
# 安装全局serve
npm i serve -g
# 启动服务器,将build目录下所有资源作为静态资源暴露出去
serve -s build
可能出现的问题,
-
1.Eslint
eslint不认识 window、navigator全局变量
解决:需要修改package.json中eslintConfig配置 "env": { "browser": true // 支持浏览器端全局变量 } -
sw代码必须运行在服务器上
npm i serve -g serve -s build 启动服务器,将build目录下所有资源作为静态资源暴露出去
10.多进程打包
只有工作消耗时间比较长,才需要多进程打包
开启多进程打包。
进程启动大概为600ms,进程通信也有开销。
只有工作消耗时间比较长,才需要多进程打包
正常来讲,一个文件只能被一个loader处理。
当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:
先执行eslint 在执行babel
安装
npm i thread-loader -D
提供给babel配置
// file: webpack.config.js ->添加loader
{
test: /\.js$/,
exclude: /node_modules/,
use: [
//开启多进程
{
loader: 'thread-loader',
options: {
workers: 2 // 进程2个
}
},
{
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: { version: 3 },
targets: {
chrome: '60',
firefox: '50'
}
}
]
],
// 开启babel缓存
// 第二次构建时,会读取之前的缓存
cacheDirectory: true
}
}
]
},
11.externals
忽略npm文件的打包
在index.html文件中用
<script>进行引入</script>例如
<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
配置
// file: webpack.config.js
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'production',
externals: {
// 拒绝jQuery被打包进来,npm包名
jquery: 'jQuery',
// react:'React'
}
};
重新引入
<!-- file: index.html -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js"></script>
12. DLL 单独库文件
动态连接库,将库打包单独打包
使用dll技术,对某些库(第三方库:jquery、react、vue...)进行单独打包 当你运行 webpack 时,默认查找 webpack.config.js 配置文件 需求:需要运行 webpack.dll.js 文件 --> webpack --config webpack.dll.js
打包命令
1.先打包dll文件
webpack --config webpack.dll.js
2.打包整个项目
webpack
安装
npm i add-asset-html-webpack-plugin -D
新建webpack.dll.js 配置文件
例如: 单独处理jQuery包/ 单独处理react, react-dom ,react-router-dom等文件
const { resolve } = require('path');
const webpack = require('webpack');
module.exports = {
entry: {
// 最终打包生成的[name] --> jquery
// ['jquery'] --> 要打包的库是jquery
jquery: ['jquery'],
react:['react','react-dom','react-router-dom']
},
output: {
filename: '[name].js',
path: resolve(__dirname, 'dll'),
library: '[name]_[hash:10]' // 打包的库里面向外暴露出去的内容叫什么名字
},
plugins: [
// 打包生成一个 manifest.json --> 提供和jquery映射
new webpack.DllPlugin({
name: '[name]_[hash:10]', // 映射库的暴露的内容名称
path: resolve(__dirname, 'dll/manifest.json') // 输出文件路径
})
],
mode: 'production'
};
由于DLL文件已经打包过node包jQuery了, 那么webpack.config.json就不用再打包相同的文件了
对Webpack.config.json进行处理
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
+ const webpack = require('webpack');
+ const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
// 告诉webpack哪些库不参与打包,同时使用时的名称也得变~
+ new webpack.DllReferencePlugin({
+ manifest: resolve(__dirname, 'dll/manifest.json')
+ }),
// 将某个文件打包输出去,并在html中自动引入该资源
+ new AddAssetHtmlWebpackPlugin({
+ filepath: resolve(__dirname, 'dll/jquery.js')
+ })
],
mode: 'production'
};
进行打包
# 先生成单独打包的文件
webpack --config webpack.dll.js
# 再进行打包构建
webpack
13.优化性能总结
开发环境性能优化
- 优化打包构建速度
- HMR
- 优化代码调试
- source-map
生产环境性能优化
- 优化打包构建速度
- oneOf
- babel缓存
- 多进程打包
- externals 忽略打包
- dll 单独打包
- 优化代码运行的性能
- 缓存(hash-chunkhash-contenthash)
- tree shaking 树摇,去除无用的代码, 例如没有调用的函数
- code split 代码分割
- 懒加载/预加载
- pwa 离线访问
webPack 5注意点
此版本重点关注以下内容:
- 通过持久缓存提高构建性能.
- 使用更好的算法和默认值来改善长期缓存.
- 通过更好的树摇和代码生成来改善捆绑包大小.
- 清除处于怪异状态的内部结构,同时在 v4 中实现功能而不引入任何重大更改.
- 通过引入重大更改来为将来的功能做准备,以使我们能够尽可能长时间地使用 v5.
1.下载
- npm i webpack webpack-cli -D
2.自动删除 Node.js Polyfills
早期,webpack 的目标是允许在浏览器中运行大多数 node.js 模块,但是模块格局发生了变化,许多模块用途现在主要是为前端目的而编写的。webpack <= 4 附带了许多 node.js 核心模块的 polyfill,一旦模块使用任何核心模块(即 crypto 模块),这些模块就会自动应用。
尽管这使使用为 node.js 编写的模块变得容易,但它会将这些巨大的 polyfill 添加到包中。在许多情况下,这些 polyfill 是不必要的。
webpack 5 会自动停止填充这些核心模块,并专注于与前端兼容的模块。
迁移:
- 尽可能尝试使用与前端兼容的模块。
- 可以为 node.js 核心模块手动添加一个 polyfill。错误消息将提示如何实现该目标。
3.Chunk 和模块 ID
添加了用于长期缓存的新算法。在生产模式下默认情况下启用这些功能。
chunkIds: "deterministic", moduleIds: "deterministic"
4.Chunk ID
你可以不用使用 import(/* webpackChunkName: "name" */ "module") 在开发环境来为 chunk 命名,生产环境还是有必要的
webpack 内部有 chunk 命名规则,不再是以 id(0, 1, 2)命名了
5.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
6.Output
webpack 4 默认只能输出 ES5 代码
webpack 5 开始新增一个属性 output.ecmaVersion, 可以生成 ES5 和 ES6 / ES2015 代码.
如:output.ecmaVersion: 2015
7.SplitChunk
// webpack4
minSize: 30000;
// webpack5
minSize: {
javascript: 30000,
style: 50000,
}
8.Caching
// 配置缓存
cache: {
// 磁盘存储
type: "filesystem",
buildDependencies: {
// 当配置修改时,缓存失效
config: [__filename]
}
}
缓存将存储到 node_modules/.cache/webpack
9.监视输出文件
之前 webpack 总是在第一次构建时输出全部文件,但是监视重新构建时会只更新修改的文件。
此次更新在第一次构建时会找到输出文件看是否有变化,从而决定要不要输出全部文件。
10.默认值
entry: "./src/index.jsoutput.path: path.resolve(__dirname, "dist")output.filename: "[name].js"