故事的开头
从一个快要下班的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
来一波在看/赞吧~