9

故事的开头

从一个快要下班的BUG开始,由于原部门同事想要基于一个项目再拆分出几个项目,我们本来用的是qiankun(基座模式)的微前端模式,再拆分其实是比较简单的

只是这次顺便在拆分之前升级了webpack5,升级也是比较简单,这里一笔带过

实施的过程没有亲自操作

问题来了,在子应用升级了webpack5以后,本地通过基座加载调试时候,突然启动不了了

复现问题

临近下班,这个事情要解决,先复现

发现network面板通过基座加载子应用时候,出现了一个js文件404

这里面很蹊跷,因为子应用单独可以启动,子应用被基座家加载时候只有一个js文件404了,而且是一个异步加载的js,那么可以判断,肯定是加载逻辑这块出了问题

在子应用中调试,打开public-path文件:

if (window.__POWERED_BY_QIANKUN__) {
    __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}

发现这些代码在通过微前端基座模式加载时候,竟然没有运行!!!是整个代码都没有被执行

这个js文件是通过入口index.tsx文件顶部引入的

已经定位到了问题,就不怕。

核心问题是:当时发现子应用的__webpack_publicPath__这个变量没有被修改,所以造成了请求的host不对,异步加载的js文件404了

由于在排查这个问题之前,我在群里说了一句,有问题大家要一起看,这样都能学到一些东西,还好我说了这句话,拉上几个同事一起来听。

其中一个同事说了一句,会不会是被webpack5给tree sharking了

我感觉是,然后让他们看看自己是怎么配置这块的,于是同事提出建议

package.json中的sideEffects字段,加上这个文件

然后再次启动项目,就解决这个问题了,public-path正常被加载了


看似简单的解决

看似简单的解决,需要先定位问题,这会用到以下几点:

熟悉微前端qiankun的原理

熟悉webpack的原理以及webpack动态懒加载实现的原理

熟悉webpack的__webpack_pulicPath__属性的意义

知道tree sharking

了解webpack5的tree sharking配置

逐个原理讲解

微前端原理

可以看我之前的手写微前端文章+源码:https://github.com/JinJieTan/...

微前端最核心的原理就是:基座项目通过配置信息,发送fetch请求,将子应用的资源全部拿到后渲染成dom节点插入到容器节点中。然后劫持路由变化事件,先在基座触发,再派发给其他子应用

webpack异步代码分割原理

同步和异步代码都会被打包成不同的js文件,由于异步加载的js文件其实是通过网络请求拿到后插入到页面中,这个异步请求的前缀,其实是可以通过__webpack__pulicPath__这个变量来设置的

这也是最早的webpack5联邦模块实现思路,可以动态加载远程js文件,只要控制这个前缀变量__webpack_pulicPath__即可

微前端+异步代码分割,核心思想是:动态的设置__webpack__publicPath__

webpack5的tree sharking配置

tree shaking 是一个术语,通常用于描述移除 JavaScript 上下文中的未引用代码(dead-code)。它依赖于 ES2015 模块语法的 静态结构 特性,例如 import 和 export。这个术语和概念实际上是由 ES2015 模块打包工具 rollup 普及起来的。

webpack 2 正式版本内置支持 ES2015 模块(也叫做 harmony modules)和未使用模块检测能力。新的 webpack 4 正式版本扩展了此检测能力,通过 package.json 的 "sideEffects" 属性作为标记,向 compiler 提供提示,表明项目中的哪些文件是 "pure(纯正 ES2015 模块)",由此可以安全地删除文件中未使用的部分。

以上是官网文档介绍

sideEffects 和 usedExports(更多被认为是 tree shaking)是两种不同的优化方式。

sideEffects 更为有效 是因为它允许跳过整个模块/文件和整个文件子树。

usedExports 依赖于 terser 去检测语句中的副作用。它是一个 JavaScript 任务而且没有像 sideEffects 一样简单直接。而且它不能跳转子树/依赖由于细则中说副作用需要被评估。尽管导出函数能运作如常,但 React 框架的高阶函数(HOC)在这种情况下是会出问题的

现在回到刚才我们被tree sharking的代码:

if (window.__POWERED_BY_QIANKUN__) {
    __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;

这个代码在上下文中其实是没有被引用的,只有在代码编译后,异步的代码js文件被加载时才能用到__webpack_public_path__这个变量,所以就被清除了代码

那么为了解决这个问题,我们需要在 package.json 中添加 "sideEffects" 属性。

它类似于 /#__PURE__/ 但是作用于模块的层面,而不是代码语句的层面。它表示的意思是(指"sideEffects" 属性):“如果被标记为无副作用的模块没有被直接导出使用,打包工具会跳过进行模块的副作用分析评估。”。

跳过public-path文件到副作用分析评估,直接打包它,就解决了这个问题

webpack的tree-sharking文档:https://webpack.docschina.org...

结尾

小小的一个问题,看似解决起来简单,但是对于日常的各种实现原理是都要求很熟悉,才能快速定位问题并且解决,这就是学习源码和各种原理的意义

感兴趣的朋友可以去我的gitHub,这些源码+文章都在https://github.com/JinJieTan/Peter- 记得给个star

喜欢的朋友帮Peter来一波在看/赞吧~


PeterTan
14.4k 声望30k 粉丝