Modern模式引发qiankun的一场“命案”

简介: 前沿:文章的起源在于开发环境中使用qiankun框架,父应用加载子应用遇到一则报错 Failed to load module script: The server responded with a non-JavaScript MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec 直接的翻译意思就是加载模块脚本失败:服务器以非JavaScript MIME类型“text/html”去响应。而也是这个问题引发了我的思考,到底是什么问题导致?

微信截图_20220514143620.png


前沿:文章的起源在于开发环境中使用qiankun框架,父应用加载子应用遇到一则报错 Failed to load module script: The server responded with a non-JavaScript MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec 直接的翻译意思就是加载模块脚本失败:服务器以非JavaScript MIME类型“text/html”去响应。而也是这个问题引发了我的思考,到底是什么问题导致?


1.思考🤔


通过分析和定位,我怀疑是在是因为我在子应用的vue-cli中使用了--modern模式编译,该模式编译会构建两份js包,一个面向支持现代浏览器的原生 ES6 包,以及一个针对其他旧浏览器的包(后面会详细说明),因为我使用的浏览器支持生 ES6,同时我们知道qiankun父应用引入子应用,本质上是将html做为入口文件,并通过import-html-entry这个库去加载子应用所需要的资源列表(js和css等),应该是因为路径的问题,导致加载js错误,再加nginx配置了try_file导致返回的html。下面我跟大家聊聊关于--modernJavascript module 以及import-html-entry原理


1.1 modern模式


Modern模式究竟是个啥,其实就是vue-cli命令行工具中的一种构建模式, 更多使用可以阅读Vue CLI


微信截图_20220514143700.png


根据官网的介绍:--modern模式是使用现代模式构建应用,为现代浏览器交付原生支持的 ES2015 代码,并生成一个兼容老浏览器的包用来自动回退。


换句话讲就是该模式下Vue CLI会构建两个版本的 js 包:一个支持现代浏览器的原生 ES2015+ 的包,以及一个兼容其他旧浏览器的包。


👨‍🎓 阿呆同学:生成两套js?这样做的目的是为了啥


答案: 我们知道低版本浏览器不支持es2015中的新特征,我们往往需要通过Babel来进行转换或者加入polyfill来支持旧版本的浏览器,但随着问题也暴露了,经过babel转换的代码code往往比原本的es2015代码更加冗长。导致文件更加庞大、性能欠缺,但其实目前有不少浏览器对es2015+(既ES6)有这不错的兼容。针对以上两种情况,Vue CLI才提供了Modern模式来解决这个问题,用来生成两套js体系,如下所示一个基于该模式编译后的html入口👇


微信截图_20220514143712.png


我们可以清晰看到对js的引入,分为下面两种情况:


  • 支持原生 ES2015+ 的浏览器: js会通过<script type="module"> 加载,并且可以使用 <link rel="modulepreload"> 预加载。
  • 不支持的浏览器: js会使用 <script nomodule> 来加载,同时忽略被定义为Module的js的文件加载


换句话说: 支持 <script type="module"> 的浏览器会忽略 <script nomodule></script> 方式引入的脚本该模式下生成的 HTML 会通过 <script type="module"><script nomodule> 进行自动降级,不需要任何特殊部署配置,原生 ES2015+ 包基本上不需添加 polyfill和Babel进行编译,能为现代浏览器提供更小、很大程度上不需要再编译的代码


👨‍🎓 啊峰 :树酱君,那你上面那个截图中间(夹在nomodule和module中间)还有一段js代码,是干嘛的?


答案:之前说到现代浏览器中都可以通过 <script type="module"> 来引入来使用ES2015+语法的代码,而能识别 type=module语法的浏览器会忽略具有nomodule属性的scripts,但Safari 10.1却不同,它并不支持nomodule属性,他会同时也把nomodule的js文件下载了,但不执行,而上述这段代码则是用来修复这个问题的。


🌲  拓展:


1.2 JavaScript modules


上一小节我们介绍了关于在Vue-cli的Module模式下生成的js文件,其中构建出版本中有一个是支持现代浏览器的原生 ES2015+ 的包,本质上就是依赖 type=module去加载 ES 模块的,而这个module是“何方神圣”,让我们进一步熟悉,首先先看看这个属性各浏览器的兼容情况


微信截图_20220514143722.png


提到模块,我相信印入你眼帘的会是exportimport这些关键字,还有就是模块自己的作用域,不会污染全局变量,只在模块中,而对这些特征的使用,也是要你告诉javascript运行环境运行的脚本是普通脚本还是一个JS module

这个时候就得使用上一节我们使用到的 <script type="module"> 来做区分引入模块文件


👩‍🎓 啊琪同学: 普通脚本和JS module之间有什么区别?


答案: 区别如下👇 :

  • 同个文件引入多次 ,JS module只会执行一次,普通脚本则会根据引入次数多次执行和解析
  • 跨域的限制:JS module需要在请求头支持Access-Control-Allow-Origin: *,普通脚本不需要
  • 执行顺序:JS module脚本默认会有defer属性,延迟脚本的执行。普通js脚本默认会阻塞html解析


微信截图_20220514143734.png


当然你也可以使用<link rel="modulepreload">让浏览器对模块进行预加载和预编译:模块和它的依赖


我们来对比一下下图,同样一个文件,如果直接用Module引入,相对用babel转译过的文件引入的大小体积区别


微信截图_20220514143743.png


👨‍🎓 啊乐同学:我看有些引用的模块文件是使用 mjs 为后缀命名的哦,而不是js命名?


答案:是为了更好的区分引入的哪些文件是模块,哪些文件是常规的Javascript,也能保证你的模块可以被运行时的环境或者构建工具识别如babel和Babel等。


⏰  要注意的是,如果你是用mjs,则需要在服务器配置mime type类型,否则会报错,和文章前沿描述相似的错误Failed to load module script: The server responded with a non-JavaScript MIME type of “”. Strict MIME type checking is enforced for module scripts per HTML spec.


🌲 拓展阅读:


1.3 import-html-entry


在qiankun架构中本质上是(single-spa + sandbox + import-html-entry)用html作为入口,就是通过import-html-entry将对的子应用html中的资源进行加载,然后从入口脚本中到导出文档链接 ,看看如何使用这个库


微信截图_20220514143753.png


让我们看看这个 importHTML 方法的实现


微信截图_20220514143816.png


importHTML(url, opts = {})方法传入参数有两个


  • url:需要解析的html模版路径
  • opts:其中包括如下几个属性:fetch(用于获取远端的脚本和样式文件内容,浏览器支持的请求库)、getPublicPath(用于获取静态资源publicPath,将模板中外部资源为相对路径的转换为绝对路径)、getTemplate(支持在模板解析前,做预处理)


其中还涉及到对js、css等资源加载相关函数,在qiankun中也被使用 链接


  • getExternalStyleSheets: 用于区分css是内联还是外引(style还是link),如果是link则fetch请求资源,然后提取出内容,组成一个数组
  • getExternalScripts: 用来获取模版中出现的所有script标签,提取出内容,组成一个数组
  • execScripts: 执行所有的script中的代码(通过eval),并返回为html模板入口脚本链接entry指向的模块导出对象


微信截图_20220514143827.png


👨‍🎓 啊斌同学:那import-html-entry是如何将不同资源进行提取的?


答案: import-html-entry是使用了正则表达式来对进行 style、 link和 script等标签进行提取的,相关正则在process-tpl.js文档链接文件中,processTpl方法是解析模板的核心函数。以下是其中的部分正则


微信截图_20220514143837.png




相关文章
|
Java 开发工具 Android开发
【 uniapp 】打包Android的apk(原生APP-云打包),及发布测试
【 uniapp 】打包Android的apk(原生APP-云打包),及发布测试
【 uniapp 】打包Android的apk(原生APP-云打包),及发布测试
uniapp 如何封装uni.request请求(登录接口、业务接口)
uniapp 如何封装uni.request请求(登录接口、业务接口)
uniapp 如何封装uni.request请求(登录接口、业务接口)
|
JavaScript 前端开发 网络架构
Qiankun 微应用的路由配置方式
【10月更文挑战第4天】
793 58
|
JavaScript
Vue2中子组件调用父组件的方法,父组件调用子组件的方法,父子组件互相传值和方法调用
Vue2中子组件调用父组件的方法,父组件调用子组件的方法,父子组件互相传值和方法调用
Vue2中子组件调用父组件的方法,父组件调用子组件的方法,父子组件互相传值和方法调用
|
8月前
|
JavaScript 算法 前端开发
nodejs18版本 npm run dev失败
在使用若依框架运行 `npm run dev` 时,若卡在 95% 并报错,通常是 Node.js 17+ 与 Webpack 的兼容性问题。原因是 OpenSSL 3 的加密算法变化导致依赖冲突。解决方法:Windows 下运行 `set NODE_OPTIONS=--openssl-legacy-provider`,macOS/Linux 使用 `export NODE_OPTIONS=--openssl-legacy-provider`,然后重新启动开发服务即可。此设置让 Node.js 启用旧版加密支持,恢复正常构建流程。
764 0
|
数据可视化 搜索推荐 小程序
LowCode:低代码平台,2024国内十大主流低代码平台年终盘点
低代码平台是一种加速软件开发的高效工具,通过可视化和模型驱动的方式减少手动编码,快速构建应用。它能显著提升开发效率,降低开发成本,支持企业快速实现数字化转型。国内主流低代码平台如织信Informat、白码、钉钉宜搭等,各具特色,可根据企业需求选择合适的平台。私有化部署更是确保数据安全和定制化的重要手段。
Vue3通知提醒(Notification)
这是一个基于 Vue2 的通知提醒框组件,支持高度自定义设置,包括消息标题、自动关闭延时、弹出位置等。提供了五种样式:默认、信息、成功、警告和错误,并可通过不同方法调用以实现相应样式。组件还支持多种位置设置,如顶部左侧、顶部右侧、底部左侧和底部右侧,并允许调整与屏幕边缘的距离。
775 3
Vue3通知提醒(Notification)
|
存储 缓存 数据可视化
Cesium渲染一帧中用到的图形技术
Cesium渲染一帧中用到的图形技术
556 0
Cesium渲染一帧中用到的图形技术
|
缓存
Node——npm ERR! cb() never called!
Node——npm ERR! cb() never called!
233 0
|
JavaScript 前端开发
We‘re sorry but xxxxxx doesn‘t work properly without JavaScript enabled.
We‘re sorry but xxxxxx doesn‘t work properly without JavaScript enabled.