前言

  本文来总结写webpack 在性能方面常见的优化方案。

正文

  本文分别总结开发环境和生产环境中在打包构建速度和代码调试功能方面的优化方案,如下:

  1、开发环境性能优化

  (1)优化打包构建速度

  a、HMR: hot module replacement ,热模块替换,作用:当一个模块发生变化的时候,只会重新打包发生变化的模块,并不会打包所有模块,极大的提升了代码构建速度。

  只需要在webpack.config.js中的devserver中添加:

  devServer: {
// contentBase: resolve(__dirname, "build"),// 这个配置在新版本的webpack中使用下面的方式配置,否则会报错
static: { // static: ['assets']
directory: resolve(__dirname, "build")
},
// 启用gzip压缩
compress: true,
// 端口号
port: 3000,
open:true,// 自动打开浏览器
hot:true// 开启HMR功能
},

  执行 npx webpack-dev-server命令,然后修改其中的文件,会发现控制台提示修改的文件,如下:

  经测试发现总结:

  样式文件:可以使用HRM功能,因为style-loader 内部实现了

  js文件:默认不能使用HRM功能,(解决方法:修改js代码,添加支持)

  html 文件:默认不能使用HRM 功能,同时会导致html文件不能热更新了(解决方法:修改入口文件entry的引入即可,如下:)开发中不需要做

    //入口文件
entry: ["./src/index.js","./src/index.html"],

  (2)优化代码调试性能

  source-map:是一种提供源代码到构建后代码的映射技术(如果构建后代码出错,通过映射关系能够追溯到源代码错误)

  只需要在webpack.config.js中添加如下:

    devtool:"eval-source-map"

  参数:[ inline -|hidden-| eval- ] [ nosources- ] [cheap- [module-]] source-map

  source-map:默认外部,能够准确提示文件报错的具体位置和准确信息

  inline-source-map:内联。只生成一个内联的source-map,能够准确提示文件报错的具体位置和准确信息。但是体积较大

  hidden-source-map:外部,提示错误代码信息,不能追踪到源代码错误位置,只能提示到构建后代码错误位置。

  eval-source-map:内联,每个文件都会生成对应的source-map ,都在eval(),能够准确提示文件报错的具体位置和准确信息,不过多了源代码文件名加了hash值。

  nosources-source-map:外部,能够找到错误信息,但是没有任何源代码错误位置信息。

  cheap-source-map:外部,能够准确提示文件报错的具体位置和准确信息,只能精确到代码行。

  cheap-module-source-map:外部,能够准确提示文件报错的具体位置和准确信息,只能精确到代码行。但是module会将loader的 source-map 加入进来

  内联和外部的区别:外部生成了文件,而内联没有,内联构建速度更快。

  使用方法: 开发环境:速度快优先,便于调试( eval > inline > cheap > 其他),因此 eval-source-map最优

       生产环境:源代码要不要隐藏,调试要不要友好,nosources-source-map 或者 hidden-source-map

  2、生产环境性能优化

  (1)优化打包构建速度

  (2)优化代码调试性能

  a、oneOf:在loader中配置了很多个用于处理不同的文件,但是针对不同文件不能全部使用多个loader,只能使用其中一个或者几个,每次使用不需要都对loader检查一遍,因此可以对loader中代码进行改造。由于对js文件即使用了eslint-loader 又使用了babel-loader,所有把eslint-loader 提取到外部即可。如下:

 module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/, // 排除node_modules
enforce: "pre", // 优先执行,先检查eslint 再执行babel-loader
loader: "eslint-loader",
options: {
fix: true, // 自动修复eslint错误
},
},
{
oneOf: [
{
test: /\.css$/,
use: [
// "style-loader", // 创建style标签将样式放入
//这个loader取代style-loader ,作用是将提取js中的css成单独的文件
MiniCssExtractPlugin.loader,
"css-loader", // 将css文件整个到js中
/* CSS兼容性处理:postcss ==>postcss-loader postcss-preset-env
帮助postcss扎到packae.json 中browserslist里的配置,通过配置加载指定的css兼容样式
"browserlist":{
// 开发环境==》设置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"
]
}*/
// 使用loader的默认配置
// post-loader
// 修改loader配置
{
loader: "postcss-loader",
// options:{
// ident:"postcss",
// plugins:()=>{
// require("postcss-preset-env")
// }
// }
},
],
}, {
test: /\.js$/,
loader: "babel-loader",
exclude: /node_modules/, // 排除node_modules
options: {
// 预设:指示babel做哪些兼容性处理
presets: [
// "@babel/presets-env",
{
useBuiltins: "usage", // 按需加载
corejs: {
version: 3, // 指定corejs版本
},
targets: {
// 指定兼容到哪些浏览器
chorme: "60",
firefox: "60",
ie: "9",
safiri: "10",
edge: "17",
},
},
],
},
},
// 这种方式无法处理html文件中的图片
{
test: /\.(jpg|png|gif)$/,
loader: "url-loader",
options: {
// 图片大小小于8kb,会被解析为base64处理,优点减少请求数量减轻服务器压力,缺点是图片体积更大,文件请求速度更慢
limit: 8 * 1024,
esModule: false,
// 这样可以修改图片名称,[hash:10]表示取hash值的前十位,[ext]表示原文件扩展名
name: "img/[hash:8].[name].[ext]",
},
},
{
// 因为url-loader默认适用了es6模块解析,而html-loader 引入图片适用commonJS处理,解析时会出现[object Module],需要关闭url-loader的es6模块化解析
test: /\.html$/,
// 处理html 文件的img文件
loader: "html-loader",
},
{
// 打包其他资源(除了css,js,html,less,json资源以外的资源)
exclude: /\.(css|js|html|less|json)$/,
loader: "file-loader",
},
],
},
],
},

  b、缓存优化

  <1>babel缓存优化

  babel缓存指在通过babel实现 js 兼容性处理的时候,默认我们每次会对所有的js代码进行babel处理,而实际构建过程中,我们并不hi修改全部js的代码,因此只需要对我们修改的js代码进行babel兼容性处理即可,没有修改的可以使用缓存的处理就行。

  只需要在babel的配置中添加配置,如下即可:

         {
test: /\.js$/,
loader: "babel-loader",
exclude: /node_modules/, // 排除node_modules
options: {
//... 其他处理
// 开启babel缓存,第二次构建时,会读取之前的缓存
cacheDirectory: true,
},
},

  <2>打文件资源的优化

  给生成的文件添加hash值(webpack每次打包生成的唯一值),每次通过对比hash值的变化来确定是否使用缓存的文件。但是问题是:因为js和css同时使用一个hash值,重新打包,会导致所有缓存失效,无法满足缓存使用。

  给生成的文件添加 chunkhash :根据生成的hash值,如果打包来源于同一个chunk,那么hash值就一样。但是问题是:因为css是在js中引入的,所有同属于一个chunk。

  给生成的文件添加contenthash :根据文件的内容生成的hash值,不同文件hash值一定不一样。只需要在filename中添加如下代码:

 output: {
// 输出文件名
filename: "js/build.[contenthash:10]js",
// 输出路径
// __dirname 是node.js的变量,代表当前文件的目录的绝对路径
path: resolve(__dirname, "build"), // 代表输出到当前目录下创建的build文件夹下
},

  c、tree shaking:去除无用代码(js和css)

  前提:1、使用es6 模块化 2、开启production环境

  作用:减少打包代码体积

  需要在package.json 中配置如下:这样可以把一些没有使用的副作用文件保存在构建包中,比如没有css,less文件

  "sideEffects":[
"*.css",
"*.less"
]

  d、code split代码分割

  在分割之前,js文件是打包成为一个文件,然后在html中引入,无法实现我们的按需加载,对性能影响很大。

  (1)设置多入口,只要有一个入口,最终就会输出一个bundle ,通过拆分入口实现生成多个bundle

  entry:{
main:"./src/js/index.js",
test:"./src/js/index.js"
},

  (2)在webpack.config.js中添加如下配置,对项目依赖单独打包

  // 可以将node_modules中代码单独打包一个chunk输出
// 自动分析多个入口chunk中,有没有公共的文件,如果有会打包成一个单独的chunk
optimization:{
splitChunks:{
chunks:"all"
}
},

  不使用如上配置,当我们的代码中A.js 和 B.js 两个文件同时引入了 jquery 依赖的时候,都会生成对应的AB打包的文件,这两个文件中就会重复存在jquery的打包文件,这时就需要单独分离出依赖文件,单独进行打包即可。

  (3)如果不想设置多个入口文件,可以通过js代码将某个文件单打包成一个chunk

import (/*webpackChunkName:"test"*/"./test.js")
.then((res)=>{
// 文件加载成功
console.log(res);
})
.catch(()=>{
console.log("文件加载失败");
})

  通过上面的 import动态导入语法, test.js 文件就会被单独打包

  e、懒加载和预加载

  懒加载是使用上面提到的import动态导入语法,将代码放在一个异步的函数中,如下:

document.getElementById("btn").onclick = function () {
import(/*webpackChunkName:"test"*/ "./test.js")
.then((res) => {
// 文件加载成功
console.log(res);
})
.catch(() => {
console.log("文件加载失败");
});
};

  在index.js 文件中,点击btn按钮,进行test.js 文件 的懒加载,再次点击的时候,不会重复加载test文件,此时会利用缓存里的test文件即可。

  预加载prefetch,会在使用之前提前加载js文件,在使用的时候直接在缓存里面取,代码如下:

document.getElementById("btn").onclick = function () {
import(/*webpackChunkName:"test",webpackPrefetch:true*/ "./test.js")
.then((res) => {
// 文件加载成功
console.log(res);
})
.catch(() => {
console.log("文件加载失败");
});
};

  正常加载可以认为是并行加载,同一时间加载多个文件,预加载prefetch是等其他资源加载完毕,浏览器空闲的时候取加载其他资源。极大提高性能和用户体验。但是预加载兼容性较差,谨慎使用。

  f、PWA (Progressive Web App),即渐进式WEB应用。

  • 可以添加至主屏幕,点击主屏幕图标可以实现启动动画以及隐藏地址栏

  • 实现离线缓存功能,即使用户手机没有网络,依然可以使用一些离线功能

  • 实现了消息推送

    使用workbox技术 ===》workbox-webpack-plugin配置插件

    首先下载workbox-webpack-plugin库

npm i workbox-webpack-plugin -D

  在plugins中添加配置

   new WorkboxWebpackPlugin.GenerateSW({
/**
* 1.帮助serviceworker快速启动
* 2.删除旧的serviceworker
*
* 生成一个serviceworker配置文件~
*/
clientsClaim:true,
skipWaiting:true
})

  在入口文件或者html文件中可以添加如下代码注册serviceworker

// 注册serviceworker
// 处理兼容性问题
/**
* 1、eslint不能识别window.navigator这些变量,需要加package.json中的eslintConfig中配置
* "eslintConfig": {
"extends": "airbnb-base",
"env":{
"browser": true
}
},
2、 serviceworker 代码必须运行在服务器上
==》通过node.js部署
==》npm i serve -g 安装serve,然后serve -s build启动服务器,将build目录下所有资源作为静态资源暴露出去
*/
if("serviceWorker" in navigator){
window.addEventListener("load",()=>{
navigator.serviceWorker.register("/service-worker.js")// 该js文件由插件生成
.then(()=>{
console.log("注册成功");
})
.catch(()=>{
console.log("注册失败");
})
})
}

  g、thread-loader多进程打包

  安装loader:

npm i thread-loader -D

  经常给babel-loader使用:

         {
test: /\.js$/,
exclude: /node_modules/, // 排除node_modules
use: [
{
// 开启多进程打包 进程开启大概600ms,进程通信也要花时间开销
loader:"thread-loader",
options:{
workers:2,// 两个进程打包
}
},
{
loader: "babel-loader",
options: {
// 预设:指示babel做哪些兼容性处理
presets: [
// "@babel/presets-env",
{
useBuiltins: "usage", // 按需加载
corejs: {
version: 3, // 指定corejs版本
},
targets: {
// 指定兼容到哪些浏览器
chorme: "60",
firefox: "60",
ie: "9",
safiri: "10",
edge: "17",
},
},
],
// 开启babel缓存,第二次构建时,会读取之前的缓存
cacheDirectory: true,
},
},
],
},

  h、externals

  在webpack.cinfig.js 添加入下中配置

  externals:{
// 拒绝jQuery 被打包进来
jquery:"jQuery"
}

  这样jQuery这个包就不会用过npm的方式被打包到项目中,可以通过cdn的方式引入,比如在index.html 文件中插入jQuery 的script标签。通过cdn的引入,提升性能

  i、dll 对代码库进行单独打包

  创建单独的js文件,比如webpack.dll.js

/**
* 使用dll技术,对某些(第三方库:jquery、react、vue...)进行单独打包,同时生成一个manifest.json文件,提供了之间的映射关系
* 当运行webpack指令 默认运行的是webpack.config.js配置文件,需要通过webpack --config webpack.dll.js 指令运行webpack.dll.js配置文件
*/
const { resolve } = require("path");
const webpack = require("webpakck"); module.exports = {
entry: {
// 最终打包生成的[name] ==>jquery
jquery: ["jquery"],
},
output: {
filename: "[name].js",
path: resolve(__dirname, "dll"),
library: "[name]_[hash]", // 打包的库里面向外暴露出去的内容叫什么名字
},
plugins: [
// 打包生成一个manifest.json 文件(该文件提供映射关系)
new webpack.DllPlugin({
name: "[name]_[hash]", // 映射库的暴露的内容名称
path: resolve(__dirname, "dll/manifest.json"), // 输出文件路径
}),
],
mode: "production",
};

  通过上面的指令,会将jquery单独进行打包。

  然后在webpack.config.js 中引入新的插件,告诉webpack不去打包哪些依赖(忽略jquery依赖)

  plugins: [
// 告诉webpack那些库不参与打包,同时使用时的名称也得改变
new webpack.DllPlugin({
manifest:resolve(__dirname,"dll/mainfest.json")
}),
],

  然后执行下面命令下载add-asset-html-webpack-plugin

npm i add-asset-html-webpack-plugin -D

  继续如下配置(再将之前dll.js 文件打包的jquery引入进来):

  plugins: [
// 将某个文件打包输出,并在html中自动引入该资源
new AddAssetHtmlWebpackPlugin({
filepath:resolve(__dirname,"dll/jquery.js")
})
],

  通过上面的配置优化了jquery重复打包的过程提高了性能。

写在最后

  以上就是本文的全部内容,希望给读者带来些许的帮助和进步,方便的话点个关注,小白的成长之路会持续更新一些工作中常见的问题和技术点。

webpack--性能优化之打包构建速度和代码调试优化的更多相关文章

  1. vscode调试webpack的启动和打包部署过程,nodejs调试

    launch.json ``` {   // 使用 IntelliSense 了解相关属性.    // 悬停以查看现有属性的描述.   // 欲了解更多信息,请访问: https://go.micr ...

  2. Android 项目优化(一):项目代码规范优化

    项目代码规范为主要包含:类,常量,变量,ID等命名规范:注释规范:分包规范:代码风格规范. 项目代码规范是软件开发过程中非常重要的优化环节. 目前的开发社区提供了很多的开发规范文档,阿里巴巴推出了&l ...

  3. webpack 性能优化小结

    背景 如今前端工程化的概念早已经深入人心,选择一款合适的编译和资源管理工具已经成为了所有前端工程中的标配,而在诸多的构建工具中,webpack以其丰富的功能和灵活的配置而深受业内吹捧,逐步取代了gru ...

  4. [译] 优化 WEBPACK 以更快地构建 REACT

    原文地址:OPTIMIZING WEBPACK FOR FASTER REACT BUILDS 原文作者:Jonathan Rowny 译文出自:掘金翻译计划 本文永久链接:https://githu ...

  5. Webpack5构建速度提升令人惊叹,早升级早受益

    为什么要升级? webpack4用的好好的,运行稳定,为什么要升级到webpack5, 每次升级,都要经历一场地震,处理许多loader和plugin API的破坏性改变. 请给我们一个充分的升级理由 ...

  6. 嵌入式程序设计中C/C++代码的优化

    虽然使软件正确是一个工程合乎逻辑的最后一个步骤,但是在嵌入式的系统开发中,情况并不总是这样的.出于对低价产品的需求,硬件的设计者需要提供刚好足够的存储器和完成工作的处理能力.所以在嵌入式软件设计的最后 ...

  7. 嵌入式实时程序设计中C/C++代码的优化

    1 引言 计算机技术和信息技术的高速发展的今天,计算机和计算机技术大量应用在人们的日常生活中,嵌入式计算机也得到了广泛的应用.嵌入式计算机是指完成一种或多种特定功能的计算机系统,是软硬件的紧密结合体. ...

  8. 优化 Webpack 的构建速度

    1.使用高版本的 Webpack 和 Node.js 2.多进程/多实例构建:HappyPack(不维护了).thread-loader 3.压缩代码 webpack-paralle-uglify-p ...

  9. webpack 性能优化 dll 分包

    webpack 性能优化 dll 分包 html-webpack-externals-plugin DLLPlugin https://www.webpackjs.com/configuration/ ...

随机推荐

  1. 开发升讯威在线客服系统启示录:怎样编写堪比 MSDN 的用户手册

    本系列文章详细介绍使用 .net core 和 WPF 开发 升讯威在线客服与营销系统 的过程. 免费在线使用 & 免费私有化部署:https://kf.shengxunwei.com 文章目 ...

  2. Dapr 和 Azure Functions : Hello world

    本篇文章内容来自 https://charliedigital.com/2021/07/01/dapr-and-azure-functions-part-1-hello-world/ ,是按这篇文章的 ...

  3. 别人都在认真听课,我埋头写Python为主播疯狂点点点点点赞!

    最近有次在钉钉看直播,发现这个直播非常之精彩,于是情不自禁地想要为主播大佬连刷一波赞: 但我发现,手动连击点赞速度十分不可观.气人的是,钉钉直播不能长按刷赞!这让我很恼怒.心中满怀的激动和兴奋以及对大 ...

  4. 后缀自动机 (SAM)

    后缀自动机 定义 定义 SAM 为一个有限状态自动机,接受且仅接受 \(S\) 的一个后缀. 同时,SAM 是这样的自动机中最小的那个,其中状态数至多为 \(2n - 1\),转移数至多为 \(3n ...

  5. 对于fetch的理解

    在一篇文章里见到一位作者是这么说的 XMLHttpRequest 是一个设计粗糙的 API,不符合关注分离(Separation of Concerns)的原则,配置和调用方式非常混乱,而且基于事件的 ...

  6. 导出SQL语句

    转载请注明来源:https://www.cnblogs.com/hookjc/ if(!($db_conn=mysql_connect($db_server,$db_name,$db_pass))){ ...

  7. CSS快速入门(四)

    目录 CSS快速入门(四) 浮动 float属性 clear属性 浮动解决的问题及其影响 解决父标签塌陷的方法 浮动案例 定位 什么是脱离文档流 定位的两种方法 position定位 static定位 ...

  8. python——平时遇到问题记录

    # pyhs2安装 #centos yum install groupinstall 'development tools' yum install python34-devel yum instal ...

  9. sublime运行错误

      这是由于没有保存文档导致   说明: [Finished in 19.4s with exit code 1]-表示执行时间 [shell_cmd: python3 -u "/Volum ...

  10. PL/SQL批量执行SQL脚本文件

    1.选择File > New > Command Windows(命令窗口) 2.输入 @ 符号,之后敲击回车键.从本地选择执行的 SQL脚本 等待批量命令全部执行成功,关闭页面即可 新增 ...