webpack的性能优化(一)——分包优化

1.什么是分包?为什么要分包?

        默认情况下,Webpack 会将所有代码构建成一个单独的包,这在小型项目通常不会有明显的性能问题,但伴随着项目的推进,包体积逐步增长可能会导致应用的响应耗时越来越长。归根结底这种将所有资源打包成一个文件的方式存在两个弊端:

  • 资源冗余:客户端必须等待整个应用的代码包都加载完毕才能启动运行,但可能用户当下访问的内容只需要使用其中一部分代码
  • 缓存失效:将所有资源达成一个包后,所有改动 —— 即使只是修改了一个字符,客户端都需要重新下载整个代码包,缓存命中率极低

        这些问题都可以通过代码分离解决,例如 node_modules 中的资源通常变动较少,可以抽成一个独立的包,那么业务代码的频繁变动不会导致这部分第三方库资源被无意义地重复加载。

代码分离(Code Splitting) 是webpack一个非常重要的特性:
  • 它主要的目的是将代码分离到不同的bundle中,之后我们可以按需加载,或者并行加载这些文件; 比如默认情况下,所有的JavaScript代码(业务代码、第三方依赖、暂时没有用到的模块)在首页全部都加载, 就会影响首页的加载速度;
  • 代码分离可以分出出更小的bundle,以及控制资源加载优先级,提供代码的加载性能; 
Webpack中常用的代码分离有三种:
  • 入口起点:使用entry配置手动分离代码;
  • 防止重复:使用Entry Dependencies或者SplitChunksPlugin去重和分离代码;
  • 动态导入:通过模块的内联函数调用来分离代码;

2.配置多入口

入口起点的含义非常简单,就是配置多入口:
  • 比如配置一个index.js和main.js的入口;
  • 他们分别有自己的代码逻辑;
const path = require('path'); 
module.exports = { entry: { main: './src/main.js', // 第一个入口起点 app: './src/app.js' // 第二个入口起点 }, output: { filename: '[name].bundle.js', // 使用[name]占位符将生成的文件名与入口起点名称对应 path: path.resolve(__dirname, 'build') } ,};
  • 假如我们的index.js和main.js都依赖两个库:lodash、dayjs
  • 如果我们单纯的进行入口分离,那么打包后的两个bunlde都有会有一份lodash和dayjs;
事实上我们可以对他们进行共享;
const path = require('path'); 
module.exports = { entry: { main: { import: './src/main.js', dependOn: 'shared' }, // 第一个入口起点 app:  { import: './src/app.js', dependOn: 'shared' }, // 第二个入口起点 shared: ['dayjs', 'lodash'] // 共享的库}, output: { filename: '[name].bundle.js', // 使用[name]占位符将生成的文件名与入口起点名称对应 path: path.resolve(__dirname, 'dist') } };

3.SplitChunks

Webpack 提供了 SplitChunkPlugin 进行分包优化。SplitChunksPlugin 插件可以将应用程序中共享的代码拆分成单独的块,以便将其从应用程序代码中分离出来,从而提高性能和加载速度。它的优化原理如下:

3.1 SplitChunks做了什么?

分析模块之间的依赖关系

SplitChunksPlugin 会分析模块之间的依赖关系,并根据这些关系确定哪些模块可以组成一个共享块。这样可以确保代码被正确地分离,而不会出现意外的行为。

根据配置项生成共享块

SplitChunksPlugin 根据配置项生成共享块。配置项包括 minSize(指定共享块的最小大小)、maxSize(指定共享块的最大大小)、minChunks(指定一个模块至少被使用的次数才会被拆分成共享块)等。

将共享块提取出来

在分析和生成共享块后,SplitChunksPlugin 会将共享块提取出来,并创建新的 chunk(即打包后的文件),将这些共享块放入新的 chunk 中。这样,每个共享块只需被下载一次,而不必重复下载多次,从而提高了应用程序的加载速度。

将共享块缓存起来

为了进一步提高性能,SplitChunksPlugin 会将共享块缓存起来,并在后续的构建中重复使用它们。这样,如果某个共享块已经存在于缓存中,就不必再重新生成它,从而节省了构建时间。

4.动态导入

        当代码中存在不确定会被使用的模块时,最佳做法是将其分离为一个独立的 JavaScript 文件。

  • 这样可以确保在不需要该模块时,浏览器不会加载或处理该文件的 JavaScript 代码。
  • 我们平时使用的路由懒加载的就是这个原理,都是为了优化性能而延迟加载资源。

实现动态导入的方式是使用ES6的import()语法来完成。

注意:使用动态导入bar.js:
  • 在webpack中,通过动态导入获取到一个对象
  • 真正导出的内容,在该对象的default属性中,所以我们需要做一个简单的解构;

4.1 路由懒加载

动态导入最常见的使用场景就是路由懒加载

// main.js文件中
const homeBtn = document.createElement('button')
const aboutBtn = document.createElement('button')
homeBtn.textContent = '加载home文件'
aboutBtn.textContent = '加载about文件'document.body.appendChild(homeBtn)
document.body.appendChild(aboutBtn)homeBtn.addEventListener('click', () => {import('./views/home.js')
})aboutBtn.addEventListener('click', () => {import('./views/about.js')
})

打包之后的资源: 

4.2 配置打包文件的名称

但是我们会发现一个问题,从包名中无法区分是哪个文件构建后的包,我们可以通过以下方式修改打包之后的文件名:

  • output.chunkFilename
const { resolve } = require('path');module.exports = {entry: './src/main.js',output: {filename: 'bundle.js',path: resolve(__dirname, 'build'),chunkFilename: 'chunk_[name]_[id].js',},
};

默认情况下我们获取到的 [name][id] 的名称保持一致的,如果我们希望修改name的值,可以通过magic comments(魔法注释)的方式;

  • webpackChunkName 魔法注释
// main.js
homeBtn.addEventListener('click', () => {import(/* webpackChunkName: "home" */'./views/home.js') // 让webpack读取的魔法注释,固定写法
})aboutBtn.addEventListener('click', () => {import(/* webpackChunkName: "about" */'./views/about.js')
})

打包之后的资源,可以从名称看出原始文件是哪一个 

4.3 prefetch(预获取)

prefetch被用于懒加载策略。它会在浏览器空闲时,即浏览器已经加载主要资源并且有剩余带宽时,开始加载。这意味着它不会影响初始页面加载时间,因为它是在后台加载的。通常用于加载将来可能需要的资源,例如懒加载的代码块或其他不太紧急的资源。

4.4 preload(预加载)

preload用于立即加载重要资源。它会在当前页面加载时立即开始加载,而不管浏览器的空闲状态如何。因此,preload可能会影响初始页面加载性能,因为它可以竞争主要资源的带宽。通常用于加载当前页面渲染所必需的关键资源,如字体、样式表或脚本

import(/* webpackPrefetch: true */ './view/home');
import(/* webpackPreload: true */ './view/about');

5.runtime代码的分包

6.将css提取到一个独立的css文件

我们平时在打包css文件时,是通过css-loaderstyle-loader进行如下配置,最终会把css注入到页面中,

const { resolve } = require('path');module.exports = {entry: './src/main.js',output: {filename: 'bundle.js',path: resolve(__dirname, 'build'),},module: {rules: [{	//通过正则告诉webpack匹配是什么文件test: /\.css$/,use: [//  因为loader的执行顺序是从右向左(或者说从下到上,或者说从后到前							 的),所以我们需要将style-loader写到css-loader的前面;{ loader: 'style-loader' },{ loader: 'css-loader' }]}]
},
};

如果将css单独打包到一个css文件中有如下好处:

  • 分离结构和样式:将CSS独立出来可以将网页的结构(HTML)和样式(CSS)分开,使代码更加模块化和易于维护。
  • 缓存优化:独立的CSS文件可以被浏览器缓存,当用户再次访问网站时,可以减少加载时间,提高性能。

 

MiniCssExtractPlugin 可以帮助我们将css提取到一个独立的css文件中,该插件需要在webpack4+才可以使用。
  • 首先,我们需要安装 mini-css-extract-plugin:
npm install mini-css-extract-plugin -D
  • 配置rules和plugins:
const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin')module.exports = {entry: './src/main.js',output: {filename: 'bundle.js',path: resolve(__dirname, 'build'),},module: {rules: [{test: /\.css$/,use: [// 将CSS样式提取为单独的CSS文件,通过链接方式(link)引入到HTML中{ loader: MiniCssExtractPlugin.loader },  { loader: 'css-loader' }]}]
},plugins: [new MiniCssExtractPlugin({ // 使用MiniCssExtractPlugin插件filename: "css/[name]_[id].css",  // 打包后的css文件放到css文件夹中chunkFilename: "css/[name]_[id].css"})],
};

参考:

Webpack 优化实操(十一):页面分包优化 - 知乎 (zhihu.com)

webpack性能优化(一):分包 - 掘金 (juejin.cn)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/607270.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

二叉树 | 二叉树的前序遍历问题

二叉树的前序遍历问题描述 提供二叉树的根节点 root ,返回它节点值的 前序 遍历。 二叉树的前序遍历是一种深度优先遍历(DFS)的方式,其遍历顺序为:先访问根节点,然后递归地对左子树进行前序遍历&#xff…

led恒流式驱动电源芯片一览表

LED恒流式驱动电源芯片是一种用于驱动LED灯的关键组件。它能够稳定地提供恒定的电流,确保LED灯的亮度和颜色始终保持一致。 LED恒流式驱动电源芯片通常由电源管理单元、恒流输出部分和保护电路组成。电源管理单元负责转换输入电压为恒定的直流电压,并通…

App Crawler

Google官方出了一款App遍历工具App Crawler。 文档:应用抓取工具 | Android 开发者 | Android Developers App Crawler工具是Android Jetpack的一部分,它可自动的运行你的App,不需要编写或维护任何代码。 通过App Crawler运行App&…

Serverless与Kubernetes(K8s)的区别、优缺点及应用场景

Serverless与Kubernetes(K8s)的区别 架构模型 Serverless是一种基于事件驱动的计算模型,它允许开发者编写应用程序时无需关心底层的基础设施。在Serverless架构中,云服务提供商会负责管理服务器、操作系统、运行时环境等基础设施&…

数字后端设计实现之自动化useful skew技术(Concurrent Clock Data)

在数字IC后端设计实现过程中,我们一直强调做时钟树综合要把clock skew做到最小。原因是clock skew的存在对整体设计的timing是不利的。 但是具体到某些timing path,可能它的local clock skew对timing是有帮助的,比如如下图所示。 第一级FF到第…

简单易懂的PyTorch激活函数大全详解

目录 torch.nn子模块Non-linear Activations nn.ELU 主要特点与注意事项 使用方法与技巧 示例代码 图示 nn.Hardshrink Hardshrink函数定义 参数 形状 示例代码 图示 nn.Hardsigmoid Hardsigmoid函数定义 参数 形状 示例代码 图示 nn.Hardtanh HardTanh函数…

记一个常用的时间、日期 格式化方法

方法里可能有其他的逻辑,我没有删去多余的 ,仅供参考 1、对日期进行格式化 /*** 对日期进行格式化, 和C#大致一致 默认yyyy-MM-dd HH:mm:ss* 可不带参数 一个日期参数 或一个格式化参数* param date 要格式化的日期* param format 进行格式化…

【FLV】记录 H.264的解析

参考 FLV 文件格式分析 知乎大神的FLV文件格式分析。 FLV 首先下发9个字节的FLV 头 -2024-01-08 11:38:29.698 INFO [32196] [evplayer_client_main@153] player clinet run … 2024-01-08 11:38:29.702 INFO [2276] [evplayer_client_main::<lambda_1>::operator ()@14…

windows系统升级

问题 windows系统升级 详细问题 笔者手边有台电脑&#xff0c;操作系统版本为windowsXP&#xff0c;现需要升级至windows较新版本 解决方案 1、 内容备份 若C盘有重要数据文件 &#xff0c;对于C盘&#xff08;重要数据文件&#xff09;进行备份 2、下载软件天猫一键重装…

【HBase】——整合Phoenix

1 概述 Phoenix 是 HBase 的开源 SQL 皮肤。可以使用标准 JDBC API 代替 HBase 客户端 API 来创建表&#xff0c;插入数据和查询 HBase 数据。   Phoenix 在 5.0 版本默认提供有两种客户端使用&#xff08;瘦客户端和胖客户端&#xff09;&#xff0c;在 5.1.2 版本 安装包中…

【数据结构】数据结构中应用题大全(完结)

自己在学习过程中总结了DS中几乎所有的应用题&#xff0c;可以用于速通期末考/考研/各种考试。很多方法来源于B站大佬&#xff0c;底层原理本文不做过多介绍&#xff0c;建议自己研究。例题大部分选自紫皮严书。pdf版在主页资源 一、递归时间/空间分析 1.时间复杂度的分析 设…

sqlachemy orm create or delete table

from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String, DateTime ​ ​ Base declarative_base() engine create_engine(mysqlpymysql://root:123456localhost:3306/test?char…

MySQL之子查询、连接查询(内外)以及分页查询(实操)

文章目录 前言一、SQL脚本二、实操以及实现思路 前言 续上篇博主MySQL之视图&索引&执行计划这篇给大家讲解MySQL之子查询、连接查询(内&外)以及分页查询 一、SQL脚本 /*Navicat Premium Data TransferSource Server : localhostSource Server Type :…

Koodo Reader : 一个开源免费的电子书阅读器

今天在浏览 GitHub 的时候&#xff0c;偶然发现了一个非常有趣的开源项目——Koodo Reader。这个项目是一款开源免费的电子书阅读器&#xff0c;支持多种格式。它具有一些非常独特的功能&#xff0c;深深地吸引了我的注意。在接下来的内容中&#xff0c;我将为大家详细介绍一下…

站长工具之PHP单文件实现IP归属地批量查询

站长/程序员工具之PHP单程序文件实现IP归属地批量查询 支持提取IP便于直接粘贴日志&#xff0c;去重防止重复查询浪费计算资源 按出现次数排序方便分析该IP行为。查询速度极快。 <?php //整理与分享&#xff1a;yujianyue<15058593138qq.com> //注意还得放纯真IP数…

07、Kafka ------ 消息生产者(演示 发送消息) 和 消息消费者(演示 监听消息)

目录 Kafka --- 消息生产者★ 消息★ 消息的分发机制★ 分发到哪个分区★ 轮询策略&#xff08;round-robin&#xff09;★ 使用命令行工具发送消息演示添加消息 Kafka --- 消息消费者★ 消息消费者命令▲ 监听 【指定主题】 的所有消息:▲ 监听 【指定主题、指定分区】的所有消…

华为OD机试 - 启动多任务排序(Java JS Python C)

题目描述 一个应用启动时,会有多个初始化任务需要执行,并且任务之间有依赖关系,例如A任务依赖B任务,那么必须在B任务执行完成之后,才能开始执行A任务。 现在给出多条任务依赖关系的规则,请输入任务的顺序执行序列,规则采用贪婪策略,即一个任务如果没有依赖的任务,则…

LED电平显示驱动电路图

LB1409九位LED电平显示驱动电路 如图所示为LBl409九位LED电平显示驱动电路。图&#xff08;a&#xff09;是用LB1409做电平显示驱动电路&#xff0c;图&#xff08;b&#xff09;是应用基准电压电平显示驱动电路。LB1409是日本东京互洋电机株式会社生产的产品&#xff0c;与其…

开启Android学习之旅-5-Activity全屏

Android 两种方式设置全屏&#xff1a; 1. 第一行代码中的方法 通过 getWindow().getDecorView()方法拿到当前Activity的DecorView,再调用 setSystemUiVisibility() 方法来改变系统UI的显示&#xff0c;这里传入了 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 和 View.SYSTEM_UI_…

Adams许可管理安全控制策略

随着全球信息化的快速发展&#xff0c;信息安全和许可管理问题日益凸显。在这场无形的挑战中&#xff0c;Adams许可管理安全控制策略以其卓越的性能和可靠性&#xff0c;引领着解决这类问题的新潮流。 Adams许可管理安全控制策略是一种全方位、多层次的安全控制方案&#xff0…