缩小范围
-
- extensions: 指定extensions之后可以不用在require或者import的时候加文件拓展名,会依次尝试添加拓展名进行匹配
-
- alias: 配置别名可以加快webpack查找模块的速度
- 如每当引入bootstrap模块的时候,会直接引入bootstrap,而不需要从node_modules文件夹中按照模块查找规则查找
-
- modules
- 对于直接声明依赖名的模块(如react),webpack会类似node.js一样进行路径搜索,搜索node_modules目录
- 这个目录就是使用
resolve.modules字段进行配置的默认设置
-
- mainFields
- 默认情况下package.json 文件则按照文件中 main 字段的文件名来查找文件
-
- mainFiles
- 当目录下没有 package.json 文件时,我们说会默认使用目录下的 index.js 这个文件,其实这个也是可以配置的
-
- resolveLoader
- resolve.resolveLoader用于配置解析 loader 时的 resolve 配置,默认的配置如下
const bootstrap = path.resolve(__dirname,'node_modules/_bootstrap@3.3.7@bootstrap/dist/css/bootstrap.css');
resolve: {
extensions: [".js", ".jsx", ".json", ".css"],
alias: {
"bootstrap": bootstrap
},
// modules: ['node_modules'], // 默认配置
modules: [path.resolve(__dirname, 'node_modules')],
// 配置 target === "web" 或者 target === "webworker" 时 mainFields 默认值是:
mainFields: ['browser', 'module', 'main'],
// target 的值为其他时,mainFields 默认值为:
mainFields: ["module", "main"],
mainFiles: ['index'], // 你可以添加其他默认使用的文件名
}
resolveLoader: {
modules: [ 'node_modules' ],
extensions: [ '.js', '.json' ],
mainFields: [ 'loader', 'main' ]
}
noParse
- module.noParse 字段,可以用于配置哪些模块文件的内容不需要进行解析
- 不需要解析依赖(即无依赖) 的第三方大型类库等,可以通过这个字段来配置,以提高整体的构建速度
- 使用 noParse 进行忽略的模块文件中不能使用 import、require、define 等导入机制
module.exports = {
module: {
noParse: /jquery|lodash/, // 正则表达式
// 或者使用函数
noParse(content) {
return /jquery|lodash/.test(content)
},
}
}
DefinePlugin 配置全局常量
IgnorePlugin 忽略某些特定的模块,让 webpack 不把这些指定的模块打包进去
// 方式1:忽略掉全部语言包 需要哪一个再手动引入
import moment from 'moment';
import 'moment/locale/zh-cn';
new webpack.IgnorePlugin({
//A RegExp to test the context (directory) against.
contextRegExp: /moment$/,
//A RegExp to test the request against.
resourceRegExp: /^\.\/locale/
})
// 方式2:通过正则匹配忽略掉不是中文的语言包
/* new webpack.IgnorePlugin( {
//A filter function for resource and context.
checkResource: (resource, context) => {
if(/moment$/.test(context)){
if(/^\.\/locale/.test(resource)){
if(!(/zh-cn/.test(resource))){
return true;
}
}
}
return false;
}
})*/
日志优化
- 日志太多太少都不美观
- 可以修改stats
- friendly-errors-webpack-plugin
/*
errors-only 只在错误时输出
minimal 发生错误和新的编译时输出
none 没有输出
normal 标准输出
verbose 全部输出
*/
+ stats:'verbose',
plugins:[
+ new FriendlyErrorsWebpackPlugin()
]
日志输出
"scripts": {
"build": "webpack",
+ "build:stats":"webpack --json > stats.json",
"dev": "webpack-dev-server --open"
},
const webpack = require('webpack');
const config = require('./webpack.config.js');
webpack(config,(err,stats)=>{
if(err){
console.log(err);
}
if(stats.hasErrors()){
return console.error(stats.toString("errors-only"));
}
console.log(stats);
});
费时分析
const SpeedMeasureWebpackPlugin = require('speed-measure-webpack-plugin');
const smw = new SpeedMeasureWebpackPlugin();
module.exports =smw.wrap({
});
libraryTarget 和 library
- 当用 Webpack 去构建一个可以被其他模块导入使用的库时需要用到它们
- output.library 配置导出库的名称
- output.libraryExport 配置要导出的模块中哪些子模块需要被导出。 它只有在 output.libraryTarget 被设置成 commonjs 或者 commonjs2 时使用才有意义
- output.libraryTarget 配置以何种方式导出库,是字符串的枚举类型,支持以下配置
libraryTarget
var => 以全局变量的形式提供使用 commonjs => require('npm-name')['calculate'].add() commonjs2 => require('npm-name').add() this => 使用:this.calculate.add() window => window.calculate.add() global => global.calculate.add() umd => 同时支持commonjs xommonjs2 amd script
实现css文件的提取和压缩
- purgecss-webpack-plugin
- 可以去除未使用的css, 一般和glob/glob-all配合使用
- 必须和mini-css-extract-plugin配合使用
- paths路径是绝对路径 npm i purgecss-webpack-plugin mini-css-extract-plugin css-loader glob -D
const path = require("path");
+const glob = require("glob");
+const PurgecssPlugin = require("purgecss-webpack-plugin");
+const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const PATHS = {
src: path.join(__dirname, 'src')
}
module.exports = {
mode: "development",
entry: "./src/index.js",
module: {
rules: [
{
test: /\.js/,
include: path.resolve(__dirname, "src"),
use: [
{
loader: "babel-loader",
options: {
presets: ["@babel/preset-env", "@babel/preset-react"],
},
},
],
},
+ {
+ test: /\.css$/,
+ include: path.resolve(__dirname, "src"),
+ exclude: /node_modules/,
+ use: [
+ {
+ loader: MiniCssExtractPlugin.loader,
+ },
+ "css-loader",
+ ],
+ },
],
},
plugins: [
+ new MiniCssExtractPlugin({
+ filename: "[name].css",
+ }),
+ new PurgecssPlugin({
+ paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }),//true表示处理文件不处理目录
+ })
],
};
DLL --webpack5中已经废弃
- .dll为后缀的文件成为动态链接库,在一个动态链接库中可以包含给其他模块调用的函数和数据
- 把基础模块独立出来打包到单独的动态链接库里
- 当需要导入的模块在动态链接库里的时候,模块不用再次被打包,而是去动态链接库里获取
- 定义dll
- DllPlugin插件:用于打包出一个个动态连接库
- DllReferencePlugin: 在配置文件中引入DllPlugin插件打包好的动态连结库
thread-loader 多进程打包
- 把这个 loader 放置在其他 loader 之前, 放置在这个 loader 之后的 loader 就会在一个单独的 worker 池(worker pool)中运行
- thread-loader并不一定能提高打包速度,项目比较小时没必要开启多进程,可能反而会更慢
- happypack也可以实现多进程,但已废弃
rules: [
{
test: /\.js/,
include: path.resolve(__dirname, "src"),
use: [
+ {
+ loader:'thread-loader',
+ options:{
+ workers:3
+ }
+ },
{
loader: "babel-loader",
options: {
presets: ["@babel/preset-env", "@babel/preset-react"],
},
},
],
},
]
CDN
- CDN 又叫内容分发网络,通过把资源部署到世界各地,用户在访问时按照就近原则从离用户最近的服务器获取资源,从而加速资源的获取速度。
- html不缓存
- 资源文件(js css 图片)文件加上hash 长期缓存
- 为了并行加载 把静态资源分散到不同的域名上去
- 域名解析 dns-prefetch 进行域名的预解析
- 在 HTML HEAD 标签中 加入
<link rel="dns-prefetch" href="http://img.zhufengpeixun.cn">去预解析域名,以降低域名解析带来的延迟
- 在 HTML HEAD 标签中 加入
- 启用CDN之后 相对路径,都变成了绝对的指向 CDN 服务的 URL 地址
- 接入cdn
{
output: {
path: path.resolve(__dirname, 'dist'),
+ filename: '[name]_[hash:8].js',
+ publicPath: 'http://img.zhufengpeixun.cn'
},
}
- hash/chunkhash/contenthash
tree shaking
- 用到的方法才打包
- 原理是利用es6模块的特点,只能作为模块顶层语句出现 import的模块名只能是字符串常量 webpack默认支持,在.babelrc里设置modules:false即可在production mode下默认开启 "sideEffects": false 所有的代码都没有副作用(都可以进行 tree shaking) 可能会把 css / @babel/polyfill文件干掉 可以设置"sideEffects":["*.css"]
{
loader: "babel-loader",
options: {
+ presets: [["@babel/preset-env",{"modules":false}], "@babel/preset-react"],
},
},
- modules:false
代码先经过babel-loader的处理,调用babel进行编译。modules:false不会默认换import和export语法,把这个语法给webpack,webapck才能去进一步处理; modules:true 会转换import export变成commonjs的require、module.exports 这样就实现不了tree shaking了; 实现tree-shaking的前提是es module 而不能是commonjs
代码分割
- 方式
- 1.入口分割
- 2.import动态导入
- preload/prefetch
- blog.csdn.net/vivo_tech/a…
- preload 预加载
- 因为异步/延迟/插入的脚本(无论在什么位置)在网路优先级都是low
- preload-webpack-plugin
- prefetch(预先拉取)
- prefetch 跟 preload 不同,它的作用是告诉浏览器未来可能会使用到的某个资源,浏览器就会在闲时去加载对应的资源,若能预测到用户的行为,比如懒加载,点击到其它页面等则相当于提前预加载了需要的资源
- preload vs prefetch
- preload告诉浏览器马上要用到这个资源 浏览器会提升加载优先级为high
- prefetch告诉浏览器未来可能会用到这个资源 浏览器会以非常低的优先级lowest 在自己空闲的时候加载这个资源
- preload不要轻易用 只有最急需的资源才会用
- preload魔法注释需要preload-webpack-plugin生成link标签
- prefetch不需要插件配合,默认支持生成link标签
import(
`./utils.js`
/* webpackPreload: true */
/* webpackChunkName: "utils" */
)
// <link rel="preload" as="script" href="utils.js">
button.addEventListener('click', () => {
import(
`./utils.js`
/* webpackPrefetch: true */
/* webpackChunkName: "utils" */
).then(result => {
result.default.log('hello');
})
});
// <link rel="prefetch" href="utils.js" as="script">
- 提取公共代码
- 为什么要提去公共代码
- 相同的资源被重复的加载,浪费用户的流量和服务器的成本;
- 每个页面需要加载的资源太大,导致页面首屏加载缓慢 影响用户体验
- 如果能把公共代码抽离成单独文件进行加载能进行优化,可以减少网络传输流量,降低服务器成本
- 如何提取
- 基础类库 方便长期缓存
- 页面之间的共用代码
- 各个页面单独生成文件
- 概念
- module: 每一个文件都是一个模块
- chunk: 代码块 有三种情况
- 项目入口文件
- 通过import()动态引入的代码
- 通过splitchunks拆分出来的代码
- bundle: bundle是webpack打包之后的各种文件,一般就是和chunk一对一关系,bundle就是对chunk进行编译压缩打包等处理之后的产出
- 为什么要提去公共代码
optimization: {
splitChunks: {...},
runtimeChunk: true, //将运行时的工具代码提取出去
}
开启 Scope Hoisting
- 自带功能
- Scope Hoisting 可以让 Webpack 打包出来的代码文件更小、运行的更快, 它又译作 "作用域提升",是在 Webpack3 中新推出的功能。
- 初webpack转换后的模块会包裹上一层函数,import会转换成require
- 代码体积更小,因为函数申明语句会产生大量代码
- 代码在运行时因为创建的函数作用域更少了,内存开销也随之变小
- 大量作用域包裹代码会导致体积增大
- 运行时创建的函数作用域变多,内存开销增大
- scope hoisting的原理是将所有的模块按照引用顺序放在一个函数作用域里,然后适当地重命名一些变量以防止命名冲突
- 这个功能在mode为production下默认开启,开发环境要用 webpack.optimize.ModuleConcatenationPlugin插件
- 也要使用ES6 Module,CJS不支持
利用缓存
- webpack中利用缓存一般有两种
- babel-loader开启缓存
- 使用cache-loader
- babel-loader
- babel在转译js文件的时候很消耗性能,将babel-loader执行的结果缓存起来,当重新打包构建时会尝试读取缓存,来提高打包构建速度,降低消耗
{
test: /\.js$/,
exclude: /node_modules/,
use: [{
loader: "babel-loader",
options: {
+ cacheDirectory: true
}
}]
},
- cache-loader
- 在一些性能开销较大的 loader 之前添加此 loader,以将结果缓存到磁盘里
- 存和读取这些缓存文件会有一些时间开销,所以请只对性能开销较大的 loader 使用此 loader
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: [
+ 'cache-loader',
...loaders
],
include: path.resolve('src')
}
]
}
}
- oneOf
- 每个文件对于rules中的所有规则都会遍历一遍,如果使用oneOf就可以解决该问题,只要能匹配一个即可退出。(注意:在oneOf中不能两个配置处理同一种类型文件)