loader
Loader 就是将 Webpack 不认识的内容转化为认识的内容
webpack 默认支持处理 JS 与 JSON 文件,其他类型都处理不了,这里必须借助 Loader 来对不同类型的文件的进行处理。
plugin
插件(Plugin)可以贯穿 Webpack 打包的生命周期,执行不同的任务
w问题一使用 postcss-loader,自动添加 CSS3 部分属性的浏览器前缀,但是单独使用会报错需要创建 postcss 配置文件 postcss.config.js
// postcss.config.js
module.exports = {
plugins: [require('postcss-preset-env')]
}
创建 postcss-preset-env 配置文件 .browserslistrc
# 换行相当于 and
last 2 versions # 回退两个浏览器版本
> 0.5% # 全球超过0.5%人使用的浏览器,可以通过 caniuse.com 查看不同浏览器不同版本占有率
IE 10 # 兼容IE 10
还可以使用mini-css-extract-plugin这样就不用使用style-loader进而替换成MiniCssExtractPlugin.loader,并添加plugins
// ...
// 引入插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const config = {
// ...
module: {
rules: [
// ...
{
test: /\.(s[ac]|c)ss$/i, //匹配所有的 sass/scss/css 文件
use: [
// 'style-loader',
MiniCssExtractPlugin.loader, // 添加 loader
'css-loader',
'postcss-loader',
'sass-loader',
]
},
]
},
// ...
plugins:[ // 配置插件
// ...
new MiniCssExtractPlugin({ // 添加插件
filename: '[name].[hash:8].css'
}),
// ...
]
}
// ...
关于图片 webpack4是用 file-loader 和 url-loader
但是在 webpack5,内置了资源处理模块,file-loader 和 url-loader 都可以不用安装
1.14 资源模块的使用
webpack5 新增资源模块(asset module),允许使用资源文件(字体,图标等)而无需配置额外的 loader。
资源模块支持以下四个配置:
asset/resource将资源分割为单独的文件,并导出 url,类似之前的 file-loader 的功能.asset/inline将资源导出为 dataUrl 的形式,类似之前的 url-loader 的小于 limit 参数时功能.asset/source将资源导出为源码(source code). 类似的 raw-loader 功能.asset会根据文件大小来选择使用哪种类型,当文件小于 8 KB(默认) 的时候会使用 asset/inline,否则会使用 asset/resource
贴一下修改后的完整代码
js
复制代码
// ./src/index.js
const config = {
// ...
module: {
rules: [
// ...
{
test: /.(jpe?g|png|gif)$/i,
type: 'asset',
generator: {
// 输出文件位置以及文件名
// [ext] 自带 "." 这个与 url-loader 配置不同
filename: "[name][hash:8][ext]"
},
parser: {
dataUrlCondition: {
maxSize: 50 * 1024 //超过50kb不转 base64
}
}
},
{
test: /.(woff2?|eot|ttf|otf)(?.*)?$/i,
type: 'asset',
generator: {
// 输出文件位置以及文件名
filename: "[name][hash:8][ext]"
},
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 超过100kb不转 base64
}
}
},
]
},
// ...
}
module.exports = (env, argv) => {
console.log('argv.mode=',argv.mode) // 打印 mode(模式) 值
// 这里可以通过不同的模式修改 config 配置
return config;
}
执行打包,结果和之前一样
优化
1.alias 用的创建 import 或 require 的别名,用来简化模块引用,项目中基本都需要进行配置。
const config = { ... resolve:{ // 配置别名 alias: { '~': resolve('src'), '@': resolve('src'), 'components': resolve('src/components'), } } };
2 extensions
- webpack 默认配置
const config = {
//...
resolve: {
extensions: ['.js', '.json', '.wasm'],
},
};
如果用户引入模块时不带扩展名,例如
import file from '../path/to/file';
那么 webpack 就会按照 extensions 配置的数组从左到右的顺序去尝试解析模块
需要注意的是:
- 高频文件后缀名放前面;
- 手动配置后,默认配置会被覆盖
如果想保留默认配置,可以用 ... 扩展运算符代表默认配置,例如
js
复制代码
const config = {
//...
resolve: {
extensions: ['.ts', '...'],
},
};
3 modules
告诉 webpack 解析模块时应该搜索的目录,常见配置如下
const path = require('path');
// 路径处理方法
function resolve(dir){
return path.join(__dirname, dir);
}
const config = {
//...
resolve: {
modules: [resolve('src'), 'node_modules'],
},
};
告诉 webpack 优先 src 目录下查找需要解析的文件,会大大节省查找时间
4 resolveLoader
resolveLoader 与上面的 resolve 对象的属性集合相同, 但仅用于解析 webpack 的 loader 包。
一般情况下保持默认配置就可以了,但如果你有自定义的 Loader 就需要配置一下,不配可能会因为找不到 loader 报错
- 例如:我们在 loader 文件夹下面,放着我们自己写的 loader
我们就可以怎么配置
const path = require('path');
// 路径处理方法
function resolve(dir){
return path.join(__dirname, dir);
}
const config = {
//...
resolveLoader: {
modules: ['node_modules',resolve('loader')]
},
};
babel-loader 开启缓存
- babel 在转译 js 过程中时间开销比价大,将 babel-loader 的执行结果缓存起来,重新打包的时候,直接读取缓存
- 缓存位置:
node_modules/.cache/babel-loader
具体配置如下:
js
复制代码
const config = {
module: {
noParse: /jquery|lodash/,
rules: [
{
test: /.js$/i,
include: resolve('src'),
exclude: /node_modules/,
use: [
// ...
{
loader: 'babel-loader',
options: {
cacheDirectory: true // 启用缓存
}
},
]
},
// ...
]
}
}
那其他的 loader 如何将结果缓存呢?
cache-loader 就可以帮我们完成这件事情
1.6.2 cache-loader
- 缓存一些性能开销比较大的 loader 的处理结果
- 缓存位置:
node_modules/.cache/cache-loader
- 安装
bash
复制代码
$ npm i -D cache-loader
- 配置 cache-loader
js
复制代码
const config = {
module: {
// ...
rules: [
{
test: /.(s[ac]|c)ss$/i, //匹配所有的 sass/scss/css 文件
use: [
// 'style-loader',
MiniCssExtractPlugin.loader,
'cache-loader', // 获取前面 loader 转换的结果
'css-loader',
'postcss-loader',
'sass-loader',
]
},
// ...
]
}
}
1 配置optimization时让高频出现的后缀名放前面
2 externals
让header 加上jquery的cdn
externals: { jquery: 'jQuery', },
noParse
- 不需要解析依赖的第三方大型类库等,可以通过这个字段进行配置,以提高构建速度
- 使用 noParse 进行忽略的模块文件中不会解析
import、require等语法
const config = {
//...
module: {
noParse: /jquery|lodash/,
rules:[...]
}
};
thread-loader
配置在 thread-loader 之后的 loader 都会在一个单独的 worker 池(worker pool)中运行
babel-loader 开启缓存
const config = {
module: {
noParse: /jquery|lodash/,
rules: [
{
test: /\.js$/i,
include: resolve('src'),
exclude: /node_modules/,
use: [
// ...
{
loader: 'babel-loader',
options: {
cacheDirectory: true // 启用缓存
}
},
]
},
// ...
]
}
}
cache-loader
const config = {
module: {
// ...
rules: [
{
test: /\.(s[ac]|c)ss$/i, //匹配所有的 sass/scss/css 文件
use: [
// 'style-loader',
MiniCssExtractPlugin.loader,
'cache-loader', // 获取前面 loader 转换的结果
'css-loader',
'postcss-loader',
'sass-loader',
]
},
// ...
]
}
}
cache 持久化缓存
通过配置 cache 缓存生成的 webpack 模块和 chunk,来改善构建速度
const config = {
cache: {
type: 'filesystem',
},
};
Tree-shaking
splitchunk
1 入口点分割
optimization.splitChunks 是基于 SplitChunksPlugin 插件实现的
默认情况下,它只会影响到按需加载的 chunks,因为修改 initial chunks 会影响到项目的 HTML 文件中的脚本标签。 webpack 将根据以下条件自动拆分 chunks:
- 新的 chunk 可以被共享,或者模块来自于
node_modules文件夹 - 新的 chunk 体积大于 20kb(在进行 min+gz 之前的体积)
- 当按需加载 chunks 时,并行请求的最大数量小于或等于 30
- 当加载初始化页面时,并发请求的最大数量小于或等于 30
- 默认配置介绍
js
复制代码
module.exports = {
//...
optimization: {
splitChunks: {
chunks: 'async', // 有效值为 `all`,`async` 和 `initial`
minSize: 20000, // 生成 chunk 的最小体积(≈ 20kb)
minRemainingSize: 0, // 确保拆分后剩余的最小 chunk 体积超过限制来避免大小为零的模块
minChunks: 1, // 拆分前必须共享模块的最小 chunks 数。
maxAsyncRequests: 30, // 最大的按需(异步)加载次数
maxInitialRequests: 30, // 打包后的入口文件加载时,还能同时加载js文件的数量(包括入口文件)
enforceSizeThreshold: 50000,
cacheGroups: { // 配置提取模块的方案
defaultVendors: {
test: /[/]node_modules[/]/,
priority: -10,
reuseExistingChunk: true,
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
},
},
},
};
- 项目中的使用
js
复制代码
const config = {
//...
optimization: {
splitChunks: {
cacheGroups: { // 配置提取模块的方案
default: false,
styles: {
name: 'styles',
test: /.(s?css|less|sass)$/,
chunks: 'all',
enforce: true,
priority: 10,
},
common: {
name: 'chunk-common',
chunks: 'all',
minChunks: 2,
maxInitialRequests: 5,
minSize: 0,
priority: 1,
enforce: true,
reuseExistingChunk: true,
},
vendors: {
name: 'chunk-vendors',
test: /[\/]node_modules[\/]/,
chunks: 'all',
priority: 2,
enforce: true,
reuseExistingChunk: true,
},
// ... 根据不同项目再细化拆分内容
},
},
},
}
3 代码懒加载
// 按需加载 img.addEventListener('click', () => { import('./desc').then(({ default: element }) => { console.log(element) document.body.appendChild(element) }) })
作者:IT老班长
链接:https://juejin.cn/post/7023242274876162084
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。