前置条件
1、浏览器兼容目标
- ie >= 8
- firefox >= 50
- chrome >= 35
- opera >= 11.5
- '> 0.5%'
2、无界框架的浏览器兼容方案
- 无界官网: wujie-micro.github.io/doc/
- 根据 无界 官网描述,在低版本浏览器(不支持),会做降级处理,使用iframe加载,参考官网如下:wujie-micro.github.io/doc/guide/d...
3、vite 的浏览器兼容方案
具体方案可查看官网:cn.vitejs.dev/guide/build... ,重点如下
- vite自身:默认支持(转义)特定浏览器和es特性,最低支持
es2015
。 - 低版本需要使用外部插件@vitejs/plugin-legacy来支持
注意:经过后边的兼容测试,我发现 @vitejs/plugin-legacy 不是 万能的,它只会生成传统版本的 chunk 及与其相对应 ES 语言特性方面的 polyfill
这里使用@vitejs/plugin-legacy来处理浏览器兼容
4、System.register()
它允许开发者定义和使用模块,并通过异步方式加载这些模块。
System.register()
方法通常用于动态加载 JavaScript 模块。它可以接受一个模块名称或路径作为参数,然后返回一个 Promise 对象,用于异步加载和执行该模块。
这个方法的主要作用是允许开发者在运行时动态加载所需的模块,而不是在页面加载时一次性加载所有模块。这种方式可以减少页面初始化的时间,因为只有需要的功能才会被加载和执行。此外,System.register()
还支持版本控制和依赖管理,可以更好地控制不同模块之间的依赖关系。
下面是一个简单的示例,演示了如何使用 System.register()
加载一个模块:
javascript
System.register('my-module', ['dependency'], function(exports, require, module) {
// 在这里定义模块的逻辑
exports.myFunction = function() {
// 实现模块的功能
};
});
在这个示例中,System.register()
方法加载了一个名为 my-module
的模块,它依赖于 dependency
模块。在回调函数中,可以定义模块的逻辑和功能。通过 exports
参数,可以将模块的功能暴露出去,以便其他模块可以使用。
需要注意的是,System.register()
方法通常与 SystemJS 库一起使用,SystemJS 是一个 JavaScript 模块加载器和服务器的集合。使用 SystemJS 和 System.register()
方法可以实现更加灵活和可扩展的模块加载和依赖管理。
解决步骤
1、第一步:准备项目
创建项目
- main (vite + react + wujie),使用 @vitejs/plugin-legacy 做浏览器兼容,使用 @vitejs/plugin-legacy 做浏览器兼容
- vite-react(vite + react),使用 @vitejs/plugin-legacy 做浏览器兼容,使用 @vitejs/plugin-legacy 做浏览器兼容
- vite-vue(vite + vue),使用 @vitejs/plugin-legacy 做浏览器兼容
- vite-cli-vue(vite + react),这个项目用于启动(pnpm preview) cli-vue 构建的项目
- vite-static-jquery(vite + react),这个项目用于启动(pnpm preview) static-jquery 构建的项目
- cli-vue(cli + vue),使用 cli本身配置 做浏览器兼容
- static-jquery(jqury + html),支持低版本浏览器
所有项目都需要支持
- ie >= 8
- firefox >= 50
- chrome >= 35
- opera >= 11.5
- '> 0.5%'
准备完成,依次次启动,在ff 52.3 版本浏览器测试,发现两个问题
- 切换菜单遇到:Unhandled promise rejection ReferenceError: AbortController is not defined
- 低版本浏览器 无界降级成iframe加载子应用,子应用加载失败
2、第二步:解决问题:切换菜单遇到:Unhandled promise rejection ReferenceError: AbortController is not defined
通过查找编译后的js文件,确定使用了 AbortController 对象,应该是 vite 并没有 处理这个 AbortController 这个 polyfill。
这样的话就需要手动处理,我从polyfill.io官网,取到这个 polyfill 的 url:polyfill.io/v3/polyfill... ,放入到项目的index.html 文件,问题解决
3、第三步:低版本浏览器 无界降级成iframe加载子应用(vite构建的),子应用加载失败
经过调试,子应用使用 vite + react 和 vite + vue 框架的 应用 加载不出来。
报错:TypeError: document.getElementById(...) is null
查找 index.html 文件,index.html 在加载 主js的时候,使用了 System.import()
方法,无界并没有处理成功这个方法
xml
<script
nomodule
crossorigin
id="vite-legacy-entry"
data-src="/assets/index-legacy-b9959714.js"
>
System.import(
document.getElementById("vite-legacy-entry").getAttribute("data-src")
);
</script>
暂时先 改成这种加载方法:
ini
<script
nomodule
crossorigin
id="vite-legacy-entry"
src="/assets/index-legacy-b9959714.js"
>
</script>
TypeError: document.getElementById(...) is null
这个问题解决,界面依然出不来。console也没有报错信息。
因为编码后的js文件都被压缩,没有可读性。但是 在 谷歌浏览器 访问,它会格式化这个文件。这样就能查看整个 代码层级,虽然可读性依旧很差,但是能进行console或是 断点调试 了。
经过查找,查到 vite(@vitejs/plugin-legacy) 编译后 的 legacy 文件(index-legacy-3b8eb0f7),使用了 System.register()
方法,来进行主程序的异步加载
javascript
System.register([], (function(t, r) {
return {
// 主程序
}
})
在 子系统 独立运行的时候,这是没问题的。
但是 在 无界框架运行的时候,由于无界的特性,无界框架 会将 子系统的 html文件 放到 iframe中,js资源会单独放到与 存放 子系统html文件 iframe 同级别的iframe 里面。这样 System.register()
就 异步加载失败了。 有点绕,请看下图
暂时 不使用 System.register()
,即将 System.register()
里面的代码放到外边,删除 System.register()
,子系统加载出来了。
后续
System.register()
、System.import()
这些是@vitejs/plugin-legacy
构建的时候,在 polyfill 的js中添加了 System
对象,实现类似commonJs的功能。
后续会在主系统进行插件开发,加载子系统之前对子系统使用的 System.register()`、` 和
System.import() 这些
等异步加载js资源的方式进行兼容