前端打包拆分技术调研

简介: 随着单页应用的发展和前端应用需要处理的业务复杂度越来越高,我们不得不面临的问题是前端的代码量也变得越来越大。代码量的庞大一方面造成了开发编辑等待时间加长,影响开发效率,另一方面首屏加载需要更长的时间和带宽加载更庞大体积的文件。为了解决单页应用打包拆分的需求,webpack很早就开始支持多种拆分的方案...

前言

随着单页应用的发展和前端应用需要处理的业务复杂度越来越高,我们不得不面临的问题是前端的代码量也变得越来越大。代码量的庞大一方面造成了开发编辑等待时间加长,影响开发效率,另一方面首屏加载需要更长的时间和带宽加载更庞大体积的文件。

为了解决单页应用打包拆分的需求,webpack很早就开始支持多种拆分的方案。最早支持的两个方案就是多entry打包和静态或动态的Code Splitting,随着webpack升级到4.0、5.0版本,代码拆分的能力和稳定性也逐渐增强。本文主要是调研了目前最新的打包拆分技术的各种方案,并且以webpack为例,具体阐释了webpack打包拆分的具体原理。

概念术语

什么是entry?

entry就是webpack的打包入口或者叫做入口文件。从入口文件开始分析,webpack可以找到整个文件依赖的关系。

什么是bundle

bundle就是webpack经过编译、压缩、拆分后得到的一系列文件,这些文件可以直接在浏览器中运行。

什么是chunk

chunk就是webpack编译过程中,将某些模块聚合在一起,组件一个单独的文件,这就是一个chunk。一般来说,一个bundle分成多个chunk后,单个chunk无法在浏览器中直接运行。

代码拆分技术分类

以webpack为例,目前webpack提供了四种拆包的方式

  1. 多bundle技术或者多entry方式,这个方式本质就是基于多路由或者微前端将一个应用拆分成多个应用。

  2. bundle init splitting,创建许多小的chunk,但是chunk之间必须同时加载才能运行。

  3. bundle dynamic splitting,创建许多小的chunk,允许chunk按需加载

  4. Module Federation:共享模块

下面我们分别介绍下四种技术的优缺点。

多bundle技术

除了webpack内置支持的多entry实现多bundle之外,下面列举了四种多bundle技术:

基于路由的多entry

这个就是webpack内置支持的多entry方案,迁移比较简单,只需要简单修改webpack配置和配置反向代理即可。

iframe容器化

基于iframe的方案,将需要拆分的模块独立放置于iframe中。这种方式可以兼容多种不同的前端框架,但是缺点是改造成本比较高,框架通信也比较复杂。

微件化

SLS日志应用就是采取了微件化的方案,这个方案本质就是将每个app独立的打包成一个js文件(内部包含css和js)。每个app的大小都比较小,而且app的依赖可以和主项目共用,由主项目注入。微件化的方案适用于单一的前端框架,否则很难把控单个js文件的大小。

微前端

微前端是目前比较火的说法,主要是由single-spa这个项目引发的,国内比较著名的是基于single-spa的qiankun。这类方案的特点就是能够兼容多种不同的前端框架,并且提供了统一的环境、隔离机制、通信机制、生命周期等。

bundle init splitting

bundle init splitting就是将某一些文件单独打包,但是也必须和入口文件共同加载。这个方式与配置webpack的external类似,主要适用于将一些大型的库打包成外部依赖,一方面开发的时候可以加速编译时间,另一方面也能开启外部依赖的长效缓存机制。

这个方式有一个比较大的缺点就是每次页面加载的时候,被打包出去的依赖必须同时被浏览器加载、编译、运行的,如果这个包首屏用不到,会对首屏性能有一些影响。

下面是一个简单的bundle init splitting的Demo。

bundle dynamic splitting

bundle dynamic splitting就是webpack所谓的动态加载代码。这个方式的优点是代码是按需加载的,对首屏优化有非常大的帮助,而且特别适合用于react和vue组件的动态加载。缺点是代码的改造成本是比较高的,改造的时候需要借助webpack-bundle-analyzer等技术理清楚所有模块的依赖关系。

动态加载代码目前可以分为动态加载函数和动态加载react或者vue等组件。这里区分这两种方式是因为分别要让函数和组件实现动态加载的代价是不一样的。

动态加载函数

假设我们有如下两个文件:

//index.js
import callA from 'a'

init () {
  // ...other code
	callA()
  // ...other code
}

//a.js
export default function callA() {
  console.log('a')
}

如果想要将a.js让webpack作为动态代码加载,需要将调用callA的地方改为异步执行。并且用到callA的所有其他文件也需要改造,成本很高。

//index.js
const callA import('a') //异步加载语法

const init = async () => {
  // ...other code
  await callA()
  // ...other code
}

//a.js
export default function callA() {
  console.log('a')
}

动态加载react和vue组件

动态加载组件相对于函数来说方便很多,react和vue都有对应动态加载的方式,这里以react为例,只需要如下改写代码:

// a.js
export function Acom() {
	return <div>Acom</div>
}

// b.js
const Acom = lazy(() => import('./a'))
<Suspense fallback={<div />}>
	<Acom />
</Suspense>

Module Federation

Module Federation是webpack5推出的最新方案,共享模块粒度自由掌控,小到一个单独组件,大到一个完整应用。既实现了组件级别的复用,又实现了微服务的基本功能。依赖自动管理,可以共享 Host 中的依赖,版本不满足要求时自动 fallback 到 Remote 中依赖。

缺点就是更新逻辑复杂,模块更新后其他应用需要同步发版更新,也缺少应用之间的隔离机制。

结语

本文主要介绍了当前流行的前端打包拆分技术的几个方案。目前SLS也在使用这些方案优化首屏性能,主要用到了微件化、bundle init splitting、bundle dynamic splitting等方案。就我们团队目前的实践来说,单纯依赖webpack的配置实现代码拆分是非常困难的,主要有以下痛点:

  • 打包工具的代码拆分策略配置复杂,调试困难

  • 完全依赖打包工具的算法,具有极大的不确定性,少量修改会引起巨大的包拆分的变化

  • 循环依赖无法解决,容易引起线上事故

  • 面对巨石应用,无法进行异步拆分的代码基数依旧庞大。

欢迎大家评论指正。

相关文章
|
23天前
|
前端开发 JavaScript Java
前端限制打包文件数量
前端限制打包文件数量
166 65
|
3天前
|
JSON 缓存 前端开发
个人练习前端技术使用Bootstrap、JQuery、thymeleaf
个人练习前端技术使用Bootstrap、JQuery、thymeleaf
10 2
|
13天前
|
缓存 人工智能 前端开发
前端技术博客:探索现代前端开发的奥秘
前端技术博客:探索现代前端开发的奥秘
32 11
|
1月前
|
前端开发 开发者
在前端开发中,webpack 作为一个强大的模块打包工具,为我们提供了丰富的功能和扩展性
【9月更文挑战第1天】在前端开发中,Webpack 作为强大的模块打包工具,提供了丰富的功能和扩展性。本文重点介绍 DefinePlugin 插件,详细探讨其原理、功能及实际应用。DefinePlugin 可在编译过程中动态定义全局变量,适用于环境变量配置、动态加载资源、接口地址配置等场景,有助于提升代码质量和开发效率。通过具体配置示例和注意事项,帮助开发者更好地利用此插件优化项目。
65 13
|
26天前
|
Web App开发 前端开发 JavaScript
Web前端项目的跨平台桌面客户端打包方案之——CEF框架
Chromium Embedded Framework (CEF) 是一个基于 Google Chromium 项目的开源 Web 浏览器控件,旨在为第三方应用提供嵌入式浏览器支持。CEF 隔离了底层 Chromium 和 Blink 的复杂性,提供了稳定的产品级 API。它支持 Windows、Linux 和 Mac 平台,不仅限于 C/C++ 接口,还支持多种语言。CEF 功能强大,性能优异,广泛应用于桌面端开发,如 QQ、微信、网易云音乐等。CEF 开源且采用 BSD 授权,商业友好,装机量已超 1 亿。此外,GitHub 项目 CefDetector 可帮助检测电脑中使用 CEF
101 3
|
2月前
|
前端开发 JavaScript 开发者
震惊!Web 前端 href 与 src 竟有如此差异,快来一探究竟,掌握热门技术核心要点
【8月更文挑战第26天】在Web前端开发中,`href`与`src`是两个常用属性,但其差异常被忽视。`href`(超文本引用)用于创建文档间的链接关系,如链接至外部网页或引入CSS文件;`src`(来源)则用于在文档内嵌入资源,如图片或JavaScript文件。两者在使用场景及加载机制上有所不同:`href`支持并行下载且不阻塞渲染,适合非关键资源加载;而`src`加载时会暂停页面渲染直至资源加载完成,适用于如图片和脚本这类对页面显示至关重要的资源。因此,正确理解并运用这两个属性对于保障网页性能和用户体验至关重要。
41 3
|
2月前
|
存储 移动开发 前端开发
HTML5时代来临,这些新特性你掌握了吗?一篇文章带你玩转Web前端技术潮流!
【8月更文挑战第26天】HTML5(简称H5)作为新一代Web标准,相比HTML4带来了诸多增强功能。
43 2
|
2月前
|
前端开发 JavaScript 项目管理
飞跃前端瓶颈:技术进阶指南精华篇
飞跃前端瓶颈:技术进阶指南精华篇
59 1
|
2月前
|
移动开发 前端开发 JavaScript
前端需要掌握的技术有哪些方面?
前端需要掌握的技术有哪些方面?
105 1
|
2月前
|
前端开发 Java C++
超简单使用Vite+Vue3构建共享开发和分模块打包的前端项目
使用Vite和Vue3构建支持共享组件和分模块独立打包的前端项目的方法。
184 0
超简单使用Vite+Vue3构建共享开发和分模块打包的前端项目
下一篇
无影云桌面