webpack5
简册
一、基础理解
1、webpack
的作用
- 如一个
html
总会执行第一个script
标签里的js
代码,之后再执行引入的各种js
文件。 - 当然,也可以是多个
script
标签,变成了多入口。
webpack
就是指定一个或多个入口文件,然后进行代码处理,将引入的其他js,css
等等代码,资源打包成一捆一捆(bundle)的文件流(chunk),然后输出到指定的文件夹和文件名称。达到代码的兼容,压缩,转义处理等等功能。
2、webpack
的核心
-
入口起点:
entry
配置示例:
webpack.config.js
module.exports = { entry: './path/to/my/entry/file.js', // 默认为'./src/index.js' };
-
输出指定:
output
- 指定输出路基
path
:必须使用绝对路基,所以需要引入nodejs
核心模块path
- 指定输出文件名称
filename
:自定义。
配置示例:
webpack.config.js
const path = require('path') module.exports = { entry: './src/app.js' output: { path: path.resolve(__dirname, 'dist'), filename: 'build.js' } }
- 指定输出路基
-
代码翻译:
loader
webpack
是一个javascript
和json
代码的开箱即用软件,无法直接识别其他格式的文件和代码。- 此时就需要
loader
将其他代码进行翻译 - 重点:
loader
会自动识别require()/import
引入的文件名后缀,只有导入的文件会触发转译 - 通过不同的正则配置,来判断使用对应的
loader
翻译对应的软件 - 不要去想一个
loader
翻译全部的代码,毕竟有英语翻译,也有俄语翻译。 - 每一个
loader
是需要下载后才能使用的,但不需要引入到webpack.config.js
简单配置示例:
webpack.config.js
module.exports = { module: { // 配置翻译txt代码 rules: [{ test: /\.txt$/, use: 'raw-loader' }] } }
-
插件:
plugin
- 翻译(
loader
)只能翻译代码,但不能压缩,优化,管理,注入环境变量等等,更强的功能需要插件 - 翻译(
loader
)下载后可以直接使用,不需要引入 - 插件下载后不能直接使用,需要引入后才能使用
配置简单示例:
webpack.config.js
const HtmlWebpackPlugin = require('html-wbpack-plugin') // 通过npm安装 module.exports = { plugins: [ // 指定html文件为打包后dist文件内的的模板,没有其他配置就是复制 // template, 模板的意思 new HtmlWebpackPlugin({ template: './src/public/index.html' }) ] }
- 翻译(
-
模式:
mode
- 开发模式,动态热更新打包,提高打包构建速度,不需要压缩代码,隐藏源码,并提供开发调试服务器
- 生产模式,将静态资源进行打包,压缩代码,优化资源,隐藏源码等等
- 默认为生产模式
配置简单示例:
webpack.config.js
module.exports = { mode: 'production', // 配置为生产模式 // mode: 'development' // 开发模式 }
-
浏览器兼容性
-
环境
3、入口起点
-
单入口单文件写法:如下
webpack.config.js
// 写法一 module.exports = { entry: './src/index.js' } // 写法二 module.exports = { entry: { main: './src/index.js' } }
-
单入口多文件写法:一个
html
引入多个js
文件,最后打包为一个文件如下
webpack.config.js
module.exports = { entry: ['./src/index1.js', './src/index2.js'] output: { filename: 'bundle.js', }, }
-
分离第三方库:将第三方相互独立的库放在一个
js
文件内进行构建,使用vendors
关键字如下
webpack.config.js
module.export = { entry: { main: './src/index.js', vendors: './src/vendors.js' // 指定的关键字,第三方库的入口 } }
-
多入口文件写法:多个入口文件,会打包成两个文件
如下:
webpack.config.js
module.export = { entry: { a1: './src/indexA1.js', b1: './src/indexB1.js' }, output: { path: './build/js' filename: '[name].[contenthash].js' } }
-
多文件依赖关系:多个文件打包的先后依赖关系,如b文件需要a文件先引入。
如下:
webpack.config.js
module.export = { entry: { a2: 'dependingfile.js', b2: { dependOn: 'a2', // 在a2后执行 filename: 'bName', // 导出的名字,重命名为bName import: './src/app.js', }, c2: ['./src/c1.js', './src/c2.js'] }, }
-
其他:略(不知道咋用,不知道用哪里就不写了)
4、输出指定
配置如下:webpack.config.js
// 不管单文件还是多文件,还是其他优化。这一个是万精油。
module.export = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash].js'
}
}
5、代码翻译
跳转链接如下
转译css
等,转译ts
,转译图片,转译其他,处理js
,css
兼容
6、插件
跳转链接如下
二、基础使用
1、项目起步
- 通过
npm init
创建packjson
插件管理文件 - 通过
npm i webpack webpack-cli -g
全局安装一次 - 通过
npm i webpack webpack-cli -D
开发环境安装webpack - 创建
webpack.config.js
文件夹
此时已经完成起步工作
2、开始编辑
- 开发环境打包:
webpack ./src/index.js -o ./build/js --mode=development
- 生产环境打包:
webpack ./src/index.js -o ./build/js --mode=production
webpack
默认只能编译js/json
文件- 创建
webpack.config.js
文件后,使用:webpack
命令就可以构建
3、转译css
等
css
使用loader
:style-loader
,css-loader
less
使用loader
:style-loader
,css-loader
,less-loader
scss
使用loader
:style-loader
,css-loader
,sass-loader
配置如下webpack.config.js
const commonCssLoader = ['style-loader', 'css-loader']
module.exports = {
/* ... */
module: { // 配置loader的地方
rules: [ // 这个属性里面进行配置
{
test: /\.css$/, // 匹配.css文件
use: [ // 使用那些loader,执行顺序,从下向上,依次执行
'style-loader', // 创建style标签,将js中的样式资源插入到标签,并添加到head中生效
'css-loader' // 将css文件变成commonjs模块加载到js中,里面的内容是样子字符串
]
},
{
test: /\.less$/, // 匹配.less文件
use: [
...commonCssLoader, // 也可以这样引入loader
'less-loader' // 将less转为css文件,scss使用scss-loader
]
},
{
test: /\.s[ac]ss$/i, // 匹配.scss文件
use: [
...commonCssLoader,
'sass-loader' // 将s[ac]ss转为css文件,scss使用scss-loader
]
}
]
}
}
4、转译ts
- 使用
loader
:ts-loader
配置如下:webpack.config.js
module.exports = {
/* ... */
module: {
rules: [
// ts-loader 将ts转js
{ test: /\.tsx?$/, loader: "ts-loader" }
]
}
}
5、转译图片
- 使用
loader
:url-loader
,img-loader
,html-loader
配置如下:webpack.config.js
module.exports = {
/* ... */
module: {
rules: [
{
test: /\.(jpg|png|gif)$/,
use: [
{
loader: 'url-loader',
// 只使用一个loader,可以直接写loader: 使用loader名称
// 下载url-loader, file-loader
options: { // loader的配置
limit: 8 * 1024, // 小于8kb的图片会整合为大图片。减少图片流
esModule: false, // 不用es6引入
name: '[hash].[ext]' // 对图片进行重命名
},
},
{
// 图片压缩
loader: 'image-webpack-loader',
options: {
bypassOnDebug: true,
}
}
]
type: 'javascript/auto' // 不加weboack5会报错
},
{
test: /\.html$/,
loader: 'html-loader', // 处理html引入的图片,如img的src引入的资源
}
]
}
}
6、转译其他
- 其他使用
loader
:file-loader
txt
使用loader
:raw-loader
配置如下:webpack.config.js
module.exports = {
/* ... */
module: {
rules: [
// 添加loader配置
{
// 打包其他资源(处理html,js,css资源以外的资源)
// 排除html,js,css等文件以外的资源
exclude: /\.(css|js|html|json|png|jpg|gif)$/,
loader: 'file-loader',
options: {
name: '[hash].[ext]' // 不建议[hash:10],取10位hash,还是会冲突的
outputPath: 'media', // 其他资源输出路径
}
},
{ test: /\.txt$/, use: 'raw-loader' }
]
}
}
7、处理js
1、添加规范
-
作用:检测代码书写规范,逻辑规范。
-
不在
webpack.config.js
里面添加,加快打包速度(添加总报错, 无法处理) -
下载四个插件,
npm i -D
eslint
eslint-config-airbnb-base
eslint-import-resolver-webpack
eslint-plugin-import
-
pageage.json
同级创建两个文件-
.eslintignore
node_modules/ **/*.spec.* **/style/ *.html /components/test/* es/ lib/ _site/ dist/
-
.eslintrc
{ "extends": "airbnb-base", "settings": { "import/resolver": { "webpack": { "config": "webpack.config.js" } } }, "rules": { "linebreak-style": ["off", "windows"] // 不考虑换行符 // 后续添加需要的配置 } }
-
-
此时重新打开编译器,就可以看的代码检查功能的出现了
2、兼容
- 作用:将
es6
及其以上的代码转译为es5
等等 - 使用
loader
:babel-loader
- 使用插件:
@babel/preset-env
,@babel/core
,core-js
npmjs
地址:https://www.npmjs.com/package/babel-loader
配置如下:webpack.config.js
module: {
rules: [
{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' }
]
}
创建babel
配置:babel.config.js
module.exports = {
presets: [
[
"@babel/preset-env",
{
useBuiltIns: "usage", // 按需加载
corejs: { version: 3 }, // core-js版本号, 最新版本为3
targets: {
chrome: 60, // 兼容到谷歌60版本
firefox: 60 // 兼容到火狐60版本
}
}
]
],
plugins: [
[ '@babel/plugin-proposal-optional-chaining' ] // 解析 可选链式语法
]
}
3、压缩
webpack
生产模式会对js
自动进行压缩
开发模式不能压缩,需要进行代码调试
8、处理html
- 使用插件:
html-webpack-plugin
配置如下:webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
/* ... */
plugins: [
// 使用html-webpack-plugin插件
// 创建一个html文件,自动引入打包后输出的所有资源(js/css)
// 使用./src/index.html为模板,并自动引入。
// 如果没有压缩等替他配置,就是复制了模板,引入打包后资源
new HtmlWebpackPlugin({
template: './src/index.html',
hash: true,
filename: 'index.html',
minify: { // 压缩html, 一般仅在生成环境配置
collapseWhitespace: true, // 移除空格
removeComments: true // 移除注释
}
})
],
}
9、提升css
9.1、单独提取
- 作用:将
css
样式单独提出到css文件 - 使用插件:
mini-css-extract-plugin
- 注意:要使用插件携带的
loader
替换style-loader
配置如下:webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
/* ...... */
module: {
/* ... */
rules: [
{
test: /\.css$/,
use: [
// 创建style标签,将js中的样式资源插入到标签,并添加到head中生效
// 'style-loader',
// 使用mini-css-extract-plugin插件的loader替代style-loader
MiniCssExtractPlugin.loader,
'css-loader' // 解析css的loader
]
}
]
},
plugins: [
/* ... */
new MiniCssExtractPlugin({
filename: 'css/build.[hash].css' // 对提取的css进行单独命名, 不推荐使用[hash:10]
})
]
9.2、兼容
- 使用loader:
postcss-loader
,postcss-preset-env
- 注意1:需要在
package.json
里面配置browserslist
,和scripts
同级属性 - 注意2:需要设置环境变量
process.env.NODE_ENV
配置如下:webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
process.env.NODE_ENV = 'development' // 修改环境变量
// 或者通过插件cross-env进行修改,如, 在package.json里面
/*
"scripts": {
"dev": "cross-env NODE_ENV='development' webpack",
},
*/
/* ...... */
module: {
rules: [
{
test: /\.css$/,
use: [
// 'style-loader', // 创建style标签,将js中的样式资源插入到标签,并添加到head中生效
MiniCssExtractPlugin.loader, // 使用插件的loader
'css-loader', // 解析css的loader
/*
postcss-loader, postcss-preset-env 处理css兼容问题
帮助postcss去package.json中找browserlist里面的配置,通过配置加载知道的css兼容样式
默认会直接使用production里面的配置,通过环境变了process.env.NODE_ENV进行切换
process.env.NODE_ENV = "development"执行development里面的配置
*/
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
require('postcss-preset-env')(),
]
}
}
}
]
}
]
},
- 更多配置查看:https://www.cnblogs.com/both-eyes/p/10151272.html
"browserslist": {
"development": [
"last 1 chrome version", // 兼容到上一个版本的谷歌浏览器
"last 1 firefox version",
"last 1 safari version"
],
"production": [
">1%", // 兼容是市面上99%的浏览器
"not dead", // 不兼容没有维护死掉的,如ie10
"last 2 versions", // 兼容到上两个版本
"not ie <= 8"
]
}
9.3、压缩
- 使用插件:
optimize-css-assets-webpack-plugin
配置如下:webpack.config.js
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
/* ... */
plugins: [
/* ... */
new MiniCssExtractPlugin({ filename: 'css/build.css' }), // 对提取的css进行单独命名
new OptimizeCssAssetsWebpackPlugin() // 使用这个插件,就可以压缩提取后的css文件
]
10、生产模式
就是mode: 'production'
11、清除build
output
添加clean: true
就好了
- 引入插件
clean-webpack-plugin
import { CleanWebpackPlugin } from 'clean-webpack-plugin'
- 使用
new CleanWebpackPlugin()
就好了
12、简单生产
上面介绍:
css
:less/scss
转译,css
转译,css
兼容,css
压缩,css
单独提取js
:js
的规范,js
兼容,ts
转译html
:html
模板复制,html
压缩,html
内图片处理- 图片处理:图片压缩处理,
html
内图片处理 - 其他文件处理:其他文件处理
- 开发服务:
devserve
配置 - 开发模式:
mode
配置
简单配置示例:webpack.config.js
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin') // 打包html
const miniCssExtractPlugin = require('mini-css-extract-plugin') // 分离样式
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin') // 压缩css
const { CleanWebpackPlugin } = require('clean-webpack-plugin') // 清除dist
process.env.NODE_ENV = 'production'
const cssLoaders = [
miniCssExtractPlugin.loader,
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
require('postcss-preset-env')(),
]
}
}
}
]
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: resolve(__dirname, 'dist'),
clean: true,
},
module: {
rules: [
{ test: /\.css$/, use: cssLoaders },
{ test: /\.less$/, use: [...cssLoaders, 'less-loader'] },
{ test: /\.s[ac]ss$/, use: [...cssLoaders, 'sass-loader'] },
{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' },
{
test: /\.(jpg|png|gif)$/,
use: [
{
loader: 'url-loader',
options: { // loader的配置
limit: 8 * 1024,
esModule: false,
name: '[hash].[ext]'
},
},
{
loader: 'image-webpack-loader',
options: { bypassOnDebug: true }
}
],
type: 'javascript/auto'
},
{ test: /\.html$/, loader: 'html-loader' },
{ test: /\.txt$/, use: 'raw-loader' },
{
exclude: /\.(css|less|s[ac]ss|js|ts|json|html|htm|png|jpg|jpeg|gif|txt)$/,
loader: 'file-loader',
options: {
name: '[hash].[ext]',
outputPath: 'media'
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/assets/index.html',
hash: true,
filename: 'index.html',
// favicon: './src/assets/favicon.ico',
minify: {
collapseWhitespace: true,
removeComments: true
}
}),
new miniCssExtractPlugin({ filename: 'css/build.[hash].css' }),
new OptimizeCssAssetsWebpackPlugin(),
new CleanWebpackPlugin()
],
resolve: {
alias: {
'@': resolve(__dirname, 'src'),
},
},
mode: 'production',
}
使用到的插件如下:
cnpm i -D webpack webpack-cli
cnpm i -D html-webpack-plugin html-loader clean-webpack-plugin
cnpm i -D mini-css-extract-plugin optimize-css-assets-webpack-plugin style-loader css-loader postcss-loader postcss-preset-env
cnpm i -D less less-loader sass sass-loader
cnpm i -D url-loader image-webpack-loader file-loader raw-loader
cnpm i -D eslint eslint-config-airbnb-base eslint-import-resolver-webpack eslint-plugin-import
cnpm i -D babel-loader @babel/preset-env @babel/core core-js
三、高阶优化
1、devServer
- 开发过程中,模拟真实环境的服务
- 可以实现跨域请求,浏览器加载打包后文件过程等生产模式下的环境
- 同时可以进行文件热更新,方便开发和调试工作
npmjs
地址:https://www.npmjs.com/package/webpack-dev-server- 插件:
webpack-dev-server
- 下载插件:
npm i -D webpack-dev-server
// 开启服务器
devServer: {
compress: true, // 开启压缩
port: 9900, // 端口号
open: true, // 自动打开
static: ['assets'], // 静态资源读取配置
client: {
logging: 'info', // 大约基础信息
overlay: true, // 报错页面黑屏
progress: true, // 百分比显示编译进度
},
liveReload: true, // 热模块更新
proxy: { // 配置服务器代理
'/api': {
target: 'http://localhost:3000', // 代理地址
changeOrigin: true, // 允许跨域
pathRewrite: { '^/api': '' }, // 正则,把接口头部`/api`转换为''
},
'/bpi': {
target: 'http://localhost:3000', // 代理地址
changeOrigin: true, // 允许跨域
pathRewrite: { '^/bpi': '' }, // 正则,把接口头部`/api`转换为''
}
},
// 多个路径同时匹配一个地址和端口
// proxy: [
// {
// context: ['/auth', '/api'],
// target: 'http://localhost:3000',
// changeOrigin: true, // 允许跨域
// }
// ]
},
target: 'web', // 配号上面的热模块更新
2、HMR
热更新
如上面示例,
devserver
的liveReload
设置为truetarget: web
webpack5
已经可以监听js的更新了。
3、source
调试
就是浏览器调试器报错机制配置。
操作:entry
同级配置:devtool: 'source-map',
即可
不同的关键字:devtool
有不同的关键字,可以查看官网文档
开发时配置:devtool: 'eval-source-map'
或者devtool: 'eval-cheap-module-source-map'
生产时配置:devtool: 'nosource-source-map'
或者devtool:'hidden-source-map'
4、oneof-loader
-
减少
loader
匹配,加快转移速度 -
原本:
rules: [ { /* loader1 */ }, { /* loader2 */ } ]
-
修改为
rules: [ { test: /\.js$/, exclude: /mode_modules/, enforce: true, // 优先执行eslint-loader,处理一个文件只能使用一个loader的配置 loader: /eslint-loader/, options: { fix: true } }, { oneOf: [ { /* loader1 */ }, { /* loader2 */ } ] } ]
-
就是多包裹一层
-
需要使用处理
eslint
时,loader
写在oneOf
外面
5、babel
缓存🌙
存在问题。
module.exports = {
presets: [
[
"@babel/preset-env",
{
useBuiltIns: "usage", // 按需加载
corejs: 3, // corejs版本号
targets: {
chrome: 60, // 兼容到谷歌60版本
firefox: 60 // 兼容到火狐60版本
}
}
]
],
cacheDirectory: true, // 开启babel缓存,就不需要全部js代码重新转译
plugins: [
[ '@babel/plugin-proposal-optional-chaining' ] // 解析 可选链式语法
]
}
6、文件缓存
就是每次修改后,将打包的文件名字更换,达到浏览器重新请求服务器文件
使用:contenthash
:根据文件内容生成的hash值,不同的文件hash值不一样
操作:就是将js
和css
文件构建名hash
更换为contenthash
module.exports = {
entry: './src/index.js',
output: {
filename: 'js/build.[contenthash:10].js',
path: resolve(__dirname, 'build')
},
modules: {
// ...里面的静态资源文件不需要使用contenthash
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/build.[contenthash:10].css'
})
]
}
7、tree-shaking
tree shaking
条件:1、使用es6
导入到处。2、使用production
生成环境
实现:将没用使用到的node_modules
和没用使用到的代码摇下去
8、代码分割
code split
-
多入口文件分割,一个入口就会出现一个chunk
-
node-module
分割/* 1、和entry同级 2、可以将node_module中的代码单独打包一个chunk最终输出 3、自动分析多入口chunk,有没有公共的文件,如果有会打包成单独一个chunk */ optimization: { splitChunks: { chunks: 'all' } },
-
js
文件单独打包chunk
/* 1、通过js代码,将某个文件单独打包成一个chunk 2、import动态语法导入,能将整个文件单独打包 */ import(/* webpackChunkName: 'test' */ './test') .then(() => { console.log('文件加载成功') }) .catch(() => { console.log('文件打包失败') })
8、加载
-
懒加载:就是使用
import()
进行动态加载,可以和代码分割一起使用 -
预加载:就是加上注解:
webpackPrefetch: true
import(/* webpackChunkName: 'test', webpackPrefetch: true */ './test') .then(() => { console.log('文件加载成功') }) .catch(() => { console.log('文件打包失败') })
9、babel
多进程打包
下载:thread-loader
作用:注意就是减少babel翻译的次数,而且项目体积过小反而会变慢
{
test: /\.js$/,
exclude: /mode_modules/,
use: [
// 每个进程启动需要600ms
{
loader: 'thread-loader',
options: {
workers: 2 // 启动两个进程进行打包
}
},
{
loader: 'babel-loader',
options: {
presets: [
[
"@babel/preset-env",
{
useBuiltIns: true, // 按需加载
corejs: { version: 3 }, // corejs版本号
targets: {
chrome: 60, // 兼容到谷歌60版本
firefox: 60
}
}
]
],
cacheDirectory: true // 开启babel缓存,就不需要全部js代码重新转译
}
}
]
},
10、externals
处理可以使用cdn
引入的库
11、dll
将引入的库单独打包为一个chunk
-
创建
webpack.dll.js
文件const { resolve } = require('path') const webpack = require('webpack') module.exports = { entry: { // 最终打包生成的[name] ---> jquery // ['jquery'] ---> 要打包的库是jquery jquery: ['jquery'] }, output: { filename: '[name].js', path: resolve(__dirname, 'dll'), library: '[name]_[hash]' // 打包的库里面向外面暴露出去的内容叫什么名字 }, plugins: [ // 打包生成一个 manifest.json --> 提供jquery映射 new webpack.DllPlugin({ name: '[name]_[hash]', // 映射库的暴露的内容名称 path: resolve(__dirname, 'dll/manifest.json') }) ], mode: 'production' }
-
运行这个文件:
webpack --config webpack.dll.js
-
然后在
webpack.config.js
添加一些配置const webpack = require('webpack') const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin') ...... plugins: [ ......, // 告诉webpack那些库不需要打包,同时使用的名字也得变化 new webpack.DllReferencePlugin({ manifest: resolve(__dirname, 'dll/manifest.json') }), // 将某个文件打包输出去,并在html中自动引入该资源 new AddAssetHtmlWebpackPlugin({ filepath: resolve(__dirname, 'dll/jquery.js') }) ]
-
过程:
1、把
jquery
单独打包出去,避免每次重复打包2、告诉
webpack
在打包的时候不用打包jquery
3、并在
webpack
打包的使用将打包好的jquery
引入到html
里面4、其他的库是同理的