优化

开发模式

HMR

WHY:优化打包构建速度
WHAT: 模块热替换
CSS:可以使用HMR功能:因为style-loader内部实现了~
JS:默认不能使用HMR功能 —> 需要修改js代码,添加支持HMR功能的代码
注意:HMR功能对js的处理,只能处理非入口js文件的其他文件。
if (module.hot) {
// 一旦 module.hot 为true,说明开启了HMR功能。 —> 让HMR功能代码生效
module.hot.accept(‘./print.js’, function() {
// 方法会监听 print.js 文件的变化,一旦发生变化,其他模块不会重新打包构建。
// 会执行后面的回调函数
print();
});
}
html: 默认不能使用HMR功能.同时会导致问题:html文件不能热更新了~ (不用做HMR功能)
解决:修改entry入口,将html文件引入
entry: [‘./src/js/index.js’, ‘./src/index.html’],

sourcemap

WHY:如果构建后代码出错了,通过映射可以追踪源代码错误
WHAT:一种 提供源代码到构建后代码映射 技术
source-map:外部,错误信息和错误位置
inline-source-map:会以base64格式内联source-map代码,构建速度快,只生成1个source-map
错误信息和错误位置
hidden-source-map:外部 错误信息和无错误位置,只能指向构建后代码错误位置
eval-source-map:内联,每个文件都生成一个source-map,都在eval 错误信息和错误位置
nosources-source-map:外部 错误信息和错误位置 无源代码信息
cheap-source-map:外部 错误信息和错误位置 有源码 整行报错
cheap-module-source-map:外部 错误信息和错误位置 有源码
开发环境:速度快,调试好
速度eval>inline>cheap
eval-cheap-source-map
eval-source-map
调试更友好:source-map
cheap-module-source-map
cheap-source-map
———> eval-source-map /eval-cheap-module-source-map
生产环境:外联,调试友不友好
nosources-source-map全部隐藏
hidden-source-map提示构建后的信息
———-> source-map/cheap-module-source-map

oneof

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’
}
}
]
}

生产模式

缓存

  1. **babel缓存**<br /> cacheDirectory: true<br /> **--> **让第二次打包构建速度更快<br /> **文件资源缓存**<br /> **hash: **每次wepack构建时会生成一个唯一的hash值。<br /> 问题: 因为jscss同时使用一个hash值。<br /> 如果重新打包,会导致所有缓存失效。(可能我却只改动一个文件)<br /> **chunkhash:**根据chunk生成的hash值。如果打包来源于同一个chunk,那么hash值就一样<br /> 问题: jscsshash值还是一样的<br /> 因为css是在js中被引入的,所以同属于一个chunk<br /> **contenthash:** 根据文件的内容生成hash值。不同文件hash值一定不一样 <br /> --> 让代码上线运行缓存更好使用

output: {
filename: ‘js/built.[contenthash:10].js’,
path: resolve(__dirname, ‘build’)
},

{
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
}
}

tree shaking

去除无用代码

**前提:**1. 必须使用**ES6模块**化  2. 开启**production**环境<br />    **作用:** 减少代码体积<br />    在**package.json**中配置 <br />      **"sideEffects":** false 所有代码都没有副作用(都可以进行tree shaking)<br />        **问题:**可能会把css / @babel/polyfill (副作用)文件干掉<br />      **"sideEffects": **["*.css", "*.less"]

code split

单入口输出一个js文件, 多入口输出多个js文件
二 单入口:可以将node_modules中代码单独打包一个chunk最终输出
 多入口:1. 可以将node_modules中代码单独打包一个chunk最终输出
     2. 自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk
optimization: {
splitChunks: {
chunks: ‘all’
}
},
三 单入口:想打包多文件, 通过js代码,让某个文件被单独打包成一个chunk
import动态导入语法:能将某个文件单独打包
import(/ webpackChunkName: ‘test’ /‘./test’) .then(({ mul, count }) => {
// 文件加载成功~
// eslint-disable-next-line
console.log(mul(2, 5));
}) .catch(() => {
// eslint-disable-next-line
console.log(‘文件加载失败~’);
});

懒加载

懒加载~:当文件需要使用时才加载~
document.getElementById(‘btn’).onclick = function() {
import(/ webpackChunkName: ‘test’/‘./test’).then(({ mul }) => {
console.log(mul(4, 5));
});
};
预加载 prefetch:会在使用之前,提前加载js文件
等其他资源加载完毕,浏览器空闲了,再偷偷加载资源
兼容性不好
document.getElementById(‘btn’).onclick = function() {
import(/ webpackChunkName: ‘test’, webpackPrefetch: true /‘./test’).then(({ mul }) => {
console.log(mul(4, 5));
});
};

pwa

渐进式网络开发应用程序(离线可访问)
workbox —> workbox-webpack-plugin
const WorkboxWebpackPlugin = require(‘workbox-webpack-plugin’);
// webpack.config.js
plugins: [
new WorkboxWebpackPlugin.GenerateSW({
/
1. 帮助serviceworker快速启动
2. 删除旧的 serviceworker
生成一个 serviceworker 配置文件~
/
clientsClaim: true,
skipWaiting: true
})
]
//package.json
“eslintConfig”: {
“extends”: “airbnb-base”,
“env”: {
“browser”: true//要不然不识别windows会报错
}
},
// 注册serviceWorker
// 处理兼容性问题
// index.js
if (‘serviceWorker’ in navigator) {
window.addEventListener(‘load’, () => {
navigator.serviceWorker
.register(‘/service-worker.js’)
.then(() => {
console.log(‘sw注册成功了~’);
})
.catch(() => {
console.log(‘sw注册失败了~’);
});
});
}

多进程打包

进程启动大概为600ms,进程通信也有开销。
只有工作消耗时间比较长,才需要多进程打包
use: [
{
loader: ‘thread-loader’,
options: {
workers: 2 // 进程2个
}
},

externals

externals: {
// 拒绝jQuery被打包进来
jquery: ‘jQuery’
}
需要手动引入

DLL

对某些库(第三方库:jquery、react、vue…)进行单独打包
当你运行 webpack 时,默认查找 webpack.config.js 配置文件
需求:1.需要运行 webpack.dll.js 文件,一次即可
—> webpack —config webpack.dll.js
//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.js
const webpack = require(‘webpack’);
const AddAssetHtmlWebpackPlugin = require(‘add-asset-html-webpack-plugin’);
plugins: [
// 2.告诉webpack哪些库不参与打包,同时使用时的名称也得变~
new webpack.DllReferencePlugin({
manifest: resolve(dirname, ‘dll/manifest.json’)
}),
//3.将某个文件打包输出去,并在html中自动引入该资源
new AddAssetHtmlWebpackPlugin({
filepath: resolve(
dirname, ‘dll/jquery.js’)
})
],