前段时间陆续面试了一波候选人,其中提到最多的就是微前端计划,微前端不像前端框架的面试题那样,它更偏重于我的项目实战,更加考查候选人的技术水平,不像 React,Vue 轻易一问,就是各种响应式原理,Fiber 架构等等烂大巷的。
为什么抉择微前端作为我的项目亮点
如果你的简历平平无奇,面试官切实在你的简历上问不出什么,那么只能给你上点“手写题”强度了
作为面试官,我常常听到很多候选人说在公司做的我的项目很简略,平时就是堆页面,写治理端,写 H5, 没有任何亮点,我以我一次面试候选人的经验分享给大家
面试官:你为什么抉择用微前端做治理端降级,你的我的项目很宏大么?
候选人:不是的,其实是咱们把两个治理端合并,让用户方便使用。
面试官:咦,居然这样你们还不如用 a 标签链接或者 nginx 转发一下就行了,更加不便,杀鸡焉用牛刀啊
候选人:为了让客户体验到单页面的感觉,体验感更好
面试官:enen….
从这里你会感觉候选人的想法有点奇葩,然而换个角度来想,肯定要等到我的项目宏大拆服务了才用微前端么,我治理端我的项目一开始就上微前端不行么。其实从这里能够看进去,管理系统应用微前端的老本并不会太大,而且从前面的技术问答中,候选人的微前端还是挺优良的,各个细节根本都涉略到了。
如果你在公司外部很闲,又是刚好负责无关紧要的经营治理端,那么新的治理端能够一开始接入微前端计划,为将来的技术升级提供一个接口,危险也可控,还可能倒腾技术, 简历还能新增亮点,何乐而不为
另外提到 H5 了,就提多一嘴,H5 面向 C 端用户比拟多,这方面更应该关怀一些性能指标数据,比方 FP
,FCP
等等,围绕这些指标进行优化,亮点不就来了么,这类例子亘古未有,要学会多开掘
接下来是我作为面试官,常常考查候选人的问题,因为大部分候选人都是用 qiankun 框架,所以本文以 qiankun 框架为模板,重点分析我的项目实战中微前端中遇到的问题和原理
请解释一下微前端的概念以及它的次要长处和挑战?
微前端是一种将不同的前端利用组合到一起的架构模式。这些利用能够独立开发、独立部署、独立运行,而后在一个主利用中进行集成。这种模式的次要指标是解决大型、长期演进的前端我的项目的复杂性问题。
次要长处:
- 解耦: 微前端架构能够将大型项目合成为多个能够独立开发、测试和部署的小型利用。这种解耦能够进步开发效率,缩小团队间的协调老本。
- 技术栈无关: 不同的微前端利用能够应用不同的技术栈,这为应用新技术、降级旧技术提供了可能。
- 并行开发: 因为微前端利用是独立的,所以多个团队能够并行开发不同的利用,无需放心相互影响。
- 独立部署: 每个微前端利用能够独立部署,这意味着能够更快地推出新性能,同时升高了部署失败的危险。
次要挑战:
- 性能问题: 如果不同的微前端利用应用了不同的库或框架,可能会导致加载和运行的性能问题。
- 一致性: 放弃不同的微前端利用在用户体验、设计和行为上的一致性可能会比拟艰难。
- 状态共享: 在微前端利用之间共享状态可能会比较复杂,须要应用非凡的工具或模式。
- 复杂性: 只管微前端能够解决大型项目的复杂性问题,然而它本身也带来了一些复杂性,比方须要治理和协调多个独立的利用。
- 安全性: 微前端架构可能会减少跨域等平安问题。
你能详细描述一下 qiankun 微前端框架的工作原理吗?
qiankun 是一个基于 single-spa 的微前端实现框架。它的工作原理次要波及到以下几个方面:
- 利用加载:qiankun 通过动态创建 script 标签的形式加载子利用的入口文件。加载实现后,会执行子利用暴露出的生命周期函数。
- 生命周期治理:qiankun 要求每个子利用都须要暴露出 bootstrap、mount 和 unmount 三个生命周期函数。bootstrap 函数在利用加载时被调用,mount 函数在利用启动时被调用,unmount 函数在利用卸载时被调用。
- 沙箱隔离:qiankun 通过 Proxy 对象创立了一个 JavaScript 沙箱,用于隔离子利用的全局变量,避免子利用之间的全局变量净化。
- 款式隔离:qiankun 通过动静增加和移除款式标签的形式实现了款式隔离。当子利用启动时,会动静增加子利用的款式标签,当子利用卸载时,会移除子利用的款式标签。
- 通信机制:qiankun 提供了一个全局的通信机制,容许子利用之间进行通信。
在应用 qiankun 时,如果子利用是基于 jQuery 的多页利用,你会如何解决动态资源的加载问题?
在应用 qiankun 时,如果子利用是基于 jQuery 的多页利用,动态资源的加载问题可能会成为一个挑战。这是因为在微前端环境中,子利用的动态资源门路可能须要进行非凡解决能力正确加载。这里有几种可能的解决方案:
计划一:应用公共门路
在子利用的动态资源门路前增加公共门路前缀。例如,如果子利用的动态资源寄存在 http://localhost:8080/static/
,那么能够在所有的动态资源门路前增加这个前缀。
计划二:劫持标签插入函数
这个计划分为两步:
-
- 对于 HTML 中已有的 img/audio/video 等标签,qiankun 反对重写 getTemplate 函数,能够将入口文件 index.html 中的动态资源门路替换掉。
-
- 对于动静插入的 img/audio/video 等标签,劫持 appendChild、innerHTML、insertBefore 等事件,将资源的相对路径替换成绝对路径。
例如,咱们能够传递一个 getTemplate 函数,将图片的相对路径转为绝对路径,它会在解决模板时应用:
start({getTemplate(tpl,...rest) {
// 为了间接看到成果,所以写死了,理论中须要用正则匹配
return tpl.replace('<img src="./img/jQuery1.png">', '<img src="http://localhost:3333/img/jQuery1.png">');
}
});
对于动静插入的标签,劫持其插入 DOM 的函数,注入前缀。
beforeMount: app => {if(app.name === 'purehtml'){
// jQuery 的 html 办法是一个挺简单的函数,这里只是为了看成果,简写了
$.prototype.html = function(value){const str = value.replace('<img src="/img/jQuery2.png">', '<img src="http://localhost:3333/img/jQuery2.png">')
this[0].innerHTML = str;
}
}
}
计划三:给 jQuery 我的项目加上 webpack 打包
这个计划的可行性不高,都是陈年老我的项目了,没必要这样折腾。
在应用 qiankun
时,如果子利用动静插入了一些标签,你会如何解决?
在应用
qiankun
时,如果子利用动静插入了一些标签,咱们能够通过劫持 DOM 的一些办法来解决。例如,咱们能够劫持appendChild
、innerHTML
和insertBefore
等办法,将资源的相对路径替换为绝对路径。
以下是一个例子,假如咱们有一个子利用,它应用 jQuery 动静插入了一张图片:
const render = $ => {$('#app-container').html('<p>Hello, render with jQuery</p><img src="./img/my-image.png">');
return Promise.resolve();};
咱们能够在主利用中劫持 jQuery 的 html
办法,将图片的相对路径替换为绝对路径:
beforeMount: app => {if(app.name === 'my-app'){
// jQuery 的 html 办法是一个简单的函数,这里为了简化,咱们只解决 img 标签
$.prototype.html = function(value){const str = value.replace('<img src="./img/my-image.png">', '<img src="http://localhost:8080/img/my-image.png">')
this[0].innerHTML = str;
}
}
}
在这个例子中,咱们劫持了 jQuery 的 html
办法,将图片的相对路径 ./img/my-image.png
替换为了绝对路径 http://localhost:8080/img/my-image.png
。这样,无论子利用在哪里运行,图片都能够正确地加载。
在应用 qiankun
时,你如何解决老我的项目的资源加载问题?你能给出一些具体的解决方案吗?
在应用
qiankun
时,解决老我的项目的资源加载问题能够有多种计划,具体的抉择取决于我的项目的具体情况。以下是一些可能的解决方案:
- 应用
qiankun
的getTemplate
函数重写动态资源门路:对于 HTML 中已有的img/audio/video
等标签,qiankun
反对重写getTemplate
函数,能够将入口文件index.html
中的动态资源门路替换掉。例如:
start({getTemplate(tpl,...rest) {
// 为了间接看到成果,所以写死了,理论中须要用正则匹配
return tpl.replace('<img src="./img/my-image.png">', '<img src="http://localhost:8080/img/my-image.png">');
}
});
- 劫持标签插入函数:对于动静插入的
img/audio/video
等标签,咱们能够劫持appendChild
、innerHTML
、insertBefore
等事件,将资源的相对路径替换成绝对路径。例如,咱们能够劫持 jQuery 的html
办法,将图片的相对路径替换为绝对路径:
beforeMount: app => {if(app.name === 'my-app'){$.prototype.html = function(value){const str = value.replace('<img src="./img/my-image.png">', '<img src="http://localhost:8080/img/my-image.png">')
this[0].innerHTML = str;
}
}
}
- 给老我的项目加上 webpack 打包:这个计划的可行性不高,都是陈年老我的项目了,没必要这样折腾。
- 应用 iframe 嵌入老我的项目:尽管
qiankun
反对 jQuery 老我的项目,然而仿佛对多页利用没有很好的解决办法。每个页面都去批改,老本很大也很麻烦,然而应用 iframe 嵌入这些老我的项目就比拟不便。
你能解释一下 qiankun
的 start
函数的作用和参数吗?如果只有一个子项目,你会如何启用预加载?
qiankun
的start
函数是用来启动微前端利用的。在注册完所有的子利用之后,咱们须要调用start
函数来启动微前端利用。
start
函数接管一个可选的配置对象作为参数,这个对象能够蕴含以下属性:
prefetch
:预加载模式,可选值有true
、false
、'all'
、'popstate'
。默认值为true
,即在主利用start
之后即刻开始预加载所有子利用的动态资源。如果设置为'all'
,则主利用start
之后会预加载所有子利用动态资源,无论子利用是否激活。如果设置为'popstate'
,则只有在路由切换的时候才会去预加载对应子利用的动态资源。sandbox
:沙箱模式,可选值有true
、false
、{strictStyleIsolation: true}
。默认值为true
,即为每个子利用创立一个新的沙箱环境。如果设置为false
,则子利用运行在以后环境下,没有任何的隔离。如果设置为{strictStyleIsolation: true}
,则会启用严格的款式隔离模式,即子利用的款式会被齐全隔离,不会影响到其余子利用和主利用。singular
:是否为单例模式,可选值有true
、false
。默认值为true
,即一次只能有一个子利用处于激活状态。如果设置为false
,则能够同时激活多个子利用。fetch
:自定义的fetch
办法,用于加载子利用的动态资源。
如果只有一个子项目,要想启用预加载,能够这样应用 start
函数:
start({prefetch: 'all'});
这样,主利用 start
之后会预加载子利用的所有动态资源,无论子利用是否激活。
在应用 qiankun
时,你如何解决 js
沙箱不能解决的 js
净化问题?
qiankun
的js
沙箱机制次要是通过代理window
对象来实现的,它能够无效地隔离子利用的全局变量,避免子利用之间的全局变量净化。然而,这种机制并不能解决所有的js
净化问题。例如,如果咱们应用onclick
或addEventListener
给<body>
增加了一个点击事件,js
沙箱并不能打消它的影响。
对于这种状况,咱们须要依赖于良好的代码标准和开发者的盲目。在开发子利用时,咱们须要防止间接操作全局对象,如 window
和 document
。如果必须要操作,咱们应该在子利用卸载时,清理掉这些全局事件和全局变量,以避免对其余子利用或主利用造成影响。
例如,如果咱们在子利用中增加了一个全局的点击事件,咱们能够在子利用的 unmount
生命周期函数中移除这个事件:
export async function mount(props) {
// 增加全局点击事件
window.addEventListener('click', handleClick);
}
export async function unmount() {
// 移除全局点击事件
window.removeEventListener('click', handleClick);
}
function handleClick() {// 解决点击事件}
这样,当子利用卸载时,全局的点击事件也会被移除,不会影响到其余的子利用。
你能解释一下 qiankun
如何实现 keep-alive
的需要吗?
在
qiankun
中,实现keep-alive
的需要有肯定的挑战性。这是因为qiankun
的设计理念是在子利用卸载时,将环境还原到子利用加载前的状态,以避免子利用对全局环境造成净化。这种设计理念与keep-alive
的需要是相悖的,因为keep-alive
须要保留子利用的状态,而不是在子利用卸载时将其状态革除。
然而,咱们能够通过一些技巧来实现 keep-alive
的成果。一种可能的办法是在子利用的生命周期函数中保留和复原子利用的状态。例如,咱们能够在子利用的 unmount
函数中保留子利用的状态,而后在 mount
函数中复原这个状态:
// 伪代码
let savedState;
export async function mount(props) {
// 复原子利用的状态
if (savedState) {restoreState(savedState);
}
}
export async function unmount() {
// 保留子利用的状态
savedState = saveState();}
function saveState() {
// 保留子利用的状态
// 这个函数的实现取决于你的利用
}
function restoreState(state) {
// 复原子利用的状态
// 这个函数的实现取决于你的利用
}
这种办法的毛病是须要手动保留和复原子利用的状态,这可能会减少开发的复杂性。此外,这种办法也不能保留子利用的 DOM 状态,只能保留 JavaScript 的状态。
还有一种就是手动*loadMicroApp*
+display:none
,间接暗藏 Dom
另一种可能的办法是应用 single-spa
的 Parcel
性能。Parcel
是 single-spa
的一个性能,它容许你在一个利用中挂载另一个利用,并且能够管制这个利用的生命周期。通过 Parcel
,咱们能够将子利用挂载到一个暗藏的 DOM 元素上,从而实现 keep-alive
的成果。然而,这种办法须要对 qiankun
的源码进行批改,因为 qiankun
目前并不反对 Parcel
。
你能解释一下 qiankun
和 iframe
在微前端实现形式上的区别和优劣吗?在什么状况下,你会抉择应用 iframe
而不是 qiankun
?
qiankun
和 iframe
都是微前端的实现形式,但它们在实现原理和应用场景上有一些区别。
qiankun
是基于 single-spa
的微前端解决方案,它通过 JavaScript 的 import
性能动静加载子利用,而后在主利用的 DOM 中挂载子利用的 DOM。qiankun
提供了一种 JavaScript 沙箱机制,能够隔离子利用的全局变量,避免子利用之间的全局变量净化。此外,qiankun
还提供了一种款式隔离机制,能够避免子利用的 CSS 影响其余利用。这些个性使得 qiankun
在解决简单的微前端场景时具备很高的灵活性。
iframe
是一种较为传统的前端技术,它能够在一个独立的窗口中加载一个 HTML 页面。iframe
自身就是一种人造的沙箱,它能够齐全隔离子利用的 JavaScript 和 CSS,避免子利用之间的相互影响。然而,iframe
的这种隔离性也是它的毛病,因为它使得主利用和子利用之间的通信变得艰难。此外,iframe
还有一些其余的问题,比方性能问题、SEO 问题等。
在抉择 qiankun
和 iframe
时,须要依据具体的应用场景来决定。如果你的子利用是基于古代前端框架(如 React、Vue、Angular 等)开发的单页利用,那么 qiankun
可能是一个更好的抉择,因为它能够提供更好的用户体验和更高的开发效率。如果你的子利用是基于 jQuery 或者其余传统技术开发的多页利用,或者你须要在子利用中加载一些第三方的页面,那么 iframe
可能是一个更好的抉择,因为它能够提供更强的隔离性。
在应用 qiankun
时,你如何解决多个子项目的调试问题?
在应用 qiankun
解决多个子项目的调试问题时,通常的形式是将每个子项目作为一个独立的利用进行开发和调试。每个子项目都能够在本地启动,并通过批改主利用的配置,让主利用去加载本地正在运行的子利用,这样就能够对子利用进行调试了。这种形式的益处是,子利用与主利用解耦,能够独立进行开发和调试,不会相互影响。
对于如何同时启动多个子利用,你能够应用 npm-run-all
这个工具。npm-run-all
是一个 CLI 工具,能够并行或者串行执行多个 npm 脚本。这个工具对于同时启动多个子利用十分有用。应用形式如下:
- 首先,你须要在你的我的项目中装置
npm-run-all
,能够通过上面的命令进行装置:
npm install --save-dev npm-run-all
- 而后,在你的
package.json
文件中定义你须要并行运行的脚本。比方,你有两个子利用,别离为app1
和app2
,你能够定义如下的脚本:
"scripts": {
"start:app1": "npm start --prefix ./app1",
"start:app2": "npm start --prefix ./app2",
"start:all": "npm-run-all start:app1 start:app2"
}
在这个例子中,start:app1
和 start:app2
脚本别离用于启动 app1
和app2
利用,start:all
脚本则用于同时启动这两个利用。
- 最初,通过执行
npm run start:all
命令,就能够同时启动app1
和app2
这两个利用了。
npm-run-all
不仅能够并行运行多个脚本,还能够串行运行多个脚本。在某些状况下,你可能须要依照肯定的程序启动你的利用,这时你能够应用 npm-run-all
的-s
选项来串行执行脚本,例如:npm-run-all -s script1 script2
,这将会先执行script1
,而后再执行script2
。
qiankun 是如何实现 CSS 隔离的,该计划有什么毛病,还有其它计划么
qiankun
次要通过应用 Shadow DOM
来实现 CSS 隔离。
Shadow DOM
:Shadow DOM
是一种浏览器内置的 Web 规范技术,它能够创立一个关闭的 DOM 构造,这个 DOM 构造对外部是隔离的,包含其 CSS 款式。qiankun
在挂载子利用时,会将子利用的 HTML 元素挂载到Shadow DOM
上,从而实现 CSS 的隔离。
// qiankun 应用 Shadow DOM 挂载子利用
const container = document.getElementById('container');
const shadowRoot = container.attachShadow({mode: 'open'});
shadowRoot.innerHTML = '<div id="subapp-container"></div>';
对于 qiankun
的隔离计划,一个潜在的毛病是它须要浏览器反对 Shadow DOM
,这在一些旧的浏览器或者不兼容Shadow DOM
的浏览器中可能会呈现问题。
另一种可能的计划是应用 CSS 模块(CSS Modules)。CSS 模块是一种将 CSS 类名部分化的形式,能够防止全局款式抵触。在应用 CSS 模块时,每个模块的类名都会被转换成一个惟一的名字,从而实现款式的隔离。
例如,假如你有一个名为 Button
的 CSS 模块:
/* Button.module.css */
.button {background-color: blue;}
在你的 JavaScript 文件中,你能够这样引入并应用这个模块:
import styles from './Button.module.css';
function Button() {return <button className={styles.button}>Click me</button>;
}
在这个例子中,button
类名会被转换成一个惟一的名字,如Button_button__xxx
,这样就能够防止全局款式抵触了。
3.BEM 命名标准隔离
qiankun 中如何实现父子我的项目间的通信?如果让你实现一套通信机制,你该如何实现?
Actions
通信:qiankun
官网提供的通信形式,适宜业务划分清晰,较简略的微前端利用。这种通信形式次要通过setGlobalState
设置globalState
,并通过onGlobalStateChange
和offGlobalStateChange
来注册和勾销观察者
函数,从而实现通信。- 本人实现一套通信机制(能够思考一下如何追踪 State 状态,相似 Redux 模式)
- 全局变量:在全局(window)对象上定义共享的属性或办法。这种形式简单明了,但有可能导致全局净化,须要留神变量命名以防止抵触。
- 自定义事件:应用原生的 CustomEvent 或相似的第三方库来派发和监听自定义事件。这种形式防止了全局净化,更加合乎模块化的准则,但可能须要更简单的事件治理。
- 2.1. 定义一个全局的通信对象,例如 window.globalEvent,这个对象提供两个办法,emit 和 on。
-
2.2. emit 办法 用于派发事件,接管事件名称和可选的事件数据作为参数。
- 2.3. **on 办法 ** 用于监听事件,接管事件名称和回调函数作为参数。当相应的事件被派发时,回调函数将被执行。
window.globalEvent = {events: {},
emit(event, data) {if (!this.events[event]) {return;}
this.events[event].forEach(callback => callback(data));
},
on(event, callback) {if (!this.events[event]) {this.events[event] = [];}
this.events[event].push(callback);
},
};
1. 在主我的项目中应用 qiankun 注册子项目时,如何解决子项目路由的 hash 与 history 模式之争?
如果主我的项目应用 history
模式,并且子项目能够应用 history
或 hash
模式,这是 qiankun
举荐的一种模式。在这种状况下,子项目能够抉择适宜本人的路由模式,而且对于已有的子项目不须要做太多批改。然而子项目之间的跳转须要通过父我的项目的 router
对象或原生的 history
对象进行。
2. 如果主我的项目和所有子项目都采纳 hash
模式,能够有两种做法:
- 应用
path
来区分子我的项目:这种形式不须要对子我的项目进行批改,但所有我的项目之间的跳转须要借助原生的history
对象。 - 应用
hash
来区分子我的项目:这种形式能够通过自定义activeRule
来实现,但须要对子我的项目进行肯定的批改,将子项目的路由加上前缀。这样的话,我的项目之间的跳转能够间接应用各自的router
对象或<router-link>
。
3. 如果主我的项目采纳 hash
模式,而子项目中有些采纳 history
模式,这种状况下,子项目间的跳转只能借助原生的 history
对象,而不应用子项目本人的 router
对象。对于子项目,能够抉择应用 path
或 hash
来辨别不同的子项目。
在 qiankun 中,如果实现组件在不同我的项目间的共享,有哪些解决方案?
在我的项目间共享组件时,能够思考以下几种形式:
- 父子我的项目间的组件共享:主我的项目加载时,将组件挂载到全局对象(如
window
)上,在子项目中间接注册应用该组件。 - 子项目间的组件共享(弱依赖):通过主我的项目提供的全局变量,子项目挂载到全局对象上。子项目中的共享组件能够应用异步组件来实现,在加载组件前先查看全局对象中是否存在,存在则复用,否则加载组件。
- 子项目间的组件共享(强依赖):在主我的项目中通过
loadMicroApp
手动加载提供组件的子项目,确保先加载该子项目。在加载时,将组件挂载到全局对象上,并将loadMicroApp
函数传递给子项目。子项目在须要应用共享组件的中央,手动加载提供组件的子项目,期待加载实现后即可获取组件。
须要留神的是,在应用异步组件或手动加载子项目时,可能会遇到款式加载的问题,能够尝试解决该问题。另外,如果共享的组件依赖全局插件(如 store
和i18n
),须要进行非凡解决以确保插件的正确初始化。
在 qiankun 中,利用之间如何复用依赖,除了 npm 包计划外?
- 在应用
webpack
构建的子项目中,要实现复用公共依赖,须要配置webpack
的externals
,将公共依赖指定为内部依赖,不打包进子项目的代码中。 - 子项目之间的依赖复用能够通过保障依赖的 URL 统一来实现。如果多个子项目都应用同一份 CDN 文件,加载时会先从缓存读取,防止反复加载。
- 子项目复用主我的项目的依赖能够通过给子项目的
index.html
中的公共依赖的script
和link
标签增加自定义属性ignore
来实现。在qiankun
运行子项目时,qiankun
会疏忽这些带有ignore
属性的依赖,子项目独立运行时依然能够加载这些依赖。 - 在应用
qiankun
微前端框架时,可能会呈现子项目之间和主我的项目之间的全局变量抵触的问题。这是因为子项目不配置externals
时,子项目的全局Vue
变量不属于window
对象,而qiankun
在运行子项目时会先找子项目的window
,再找父我的项目的window
,导致全局变量抵触。 -
解决全局变量抵触的计划有三种:
- 计划一是在注册子项目时,在
beforeLoad
钩子函数中解决全局变量,将子项目的全局Vue
变量进行替换,以解决子项目独立运行时的全局变量抵触问题。 - 计划二是通过主我的项目将依赖通过
props
传递给子项目,子项目在独立运行时应用传递过去的依赖,防止与主我的项目的全局变量抵触。 - 计划三是批改主我的项目和子项目的依赖名称,使它们不会互相抵触,从而防止全局变量抵触的问题。
- 计划一是在注册子项目时,在
说说 webpack5 联邦模块在微前端的利用
Webpack 5 的联邦模块(Federation Module)是一个功能强大的个性,能够在微前端利用中实现模块共享和动静加载,从而提供更好的代码复用和可扩展性
1. 模块共享
Webpack 5 的联邦模块容许不同的微前端利用之间共享模块,防止反复加载和代码冗余。通过联邦模块,咱们能够将一些公共的模块抽离成一个独立的模块,并在各个微前端利用中进行援用。这样能够节俭资源,并进步利用的加载速度。
// main-app webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {ModuleFederationPlugin} = require('webpack').container;
module.exports = {
// ... 其余配置
plugins: [new HtmlWebpackPlugin(),
new ModuleFederationPlugin({
name: 'main_app',
remotes: {shared_module: 'shared_module@http://localhost:8081/remoteEntry.js',},
}),
],
};
// shared-module webpack.config.js
const {ModuleFederationPlugin} = require('webpack').container;
module.exports = {
// ... 其余配置
plugins: [
new ModuleFederationPlugin({
name: 'shared_module',
filename: 'remoteEntry.js',
exposes: {'./Button': './src/components/Button',},
}),
],
};
在上述示例中,main-app
和 shared-module
别离是两个微前端利用的 webpack 配置文件。通过 ModuleFederationPlugin
插件,shared-module
将 Button
组件裸露给其余利用应用,而 main-app
则通过 remotes
配置引入了 shared-module
。
2. 动静加载
Webpack 5 联邦模块还反对动静加载模块,这对于微前端利用的按需加载和性能优化十分有用。通过动静加载,能够在须要时动静地加载近程模块,而不是在利用初始化时一次性加载所有模块。
// main-app
const remoteModule = () => import('shared_module/Button');
// ... 其余代码
// 在须要的时候动静加载模块
remoteModule().then((module) => {
// 应用加载的模块
const Button = module.default;
// ...
});
在上述示例中,main-app
应用 import()
函数动静加载 shared_module
中的 Button
组件。通过动静加载,能够在须要时异步地加载近程模块,并在加载实现后应用模块。
在微前端利用中能够实现模块共享和动静加载,提供了更好的代码复用和可扩展性。通过模块共享,能够防止反复加载和代码冗余,而动静加载则能够按需加载模块,进步利用的性能和用户体验。
说说 qiankun 的资源加载机制(import-html-entry)
qiankun import-html-entry
是 qiankun 框架中用于加载子利用的 HTML 入口文件的工具函数。它提供了一种不便的形式来动静加载和解析子利用的 HTML 入口文件,并返回一个能够加载子利用的 JavaScript 模块。
具体而言,import-html-entry
实现了以下性能:
-
- 加载 HTML 入口文件:
import-html-entry
会通过创立一个<link>
标签来加载子利用的 HTML 入口文件。这样能够确保子利用的资源失去正确加载,并在加载实现后进行解决。
- 加载 HTML 入口文件:
-
- 解析 HTML 入口文件:一旦 HTML 入口文件加载实现,
import-html-entry
将解析该文件的内容,提取出子利用的 JavaScript 和 CSS 资源的 URL。
- 解析 HTML 入口文件:一旦 HTML 入口文件加载实现,
-
- 动静加载 JavaScript 和 CSS 资源:
import-html-entry
应用动态创建<script>
和<link>
标签的形式,依照正确的程序加载子利用的 JavaScript 和 CSS 资源。
- 动静加载 JavaScript 和 CSS 资源:
-
- 创立沙箱环境:在加载子利用的 JavaScript 资源时,
import-html-entry
会创立一个沙箱环境(sandbox),用于隔离子利用的全局变量和运行环境,避免子利用之间的抵触和净化。
- 创立沙箱环境:在加载子利用的 JavaScript 资源时,
-
- 返回子利用的入口模块:最初,
import-html-entry
返回一个能够加载子利用的 JavaScript 模块。这个模块通常是一个蕴含子利用初始化代码的函数,能够在主利用中调用以加载和启动子利用。
- 返回子利用的入口模块:最初,
通过应用 qiankun import-html-entry
,开发者能够不便地将子利用的 HTML 入口文件作为模块加载,并取得一个能够加载和启动子利用的函数,简化了子利用的加载和集成过程。
说说现有的几种微前端框架,它们的优缺点?
以下是对各个微前端框架优缺点的总结:
-
qiankun 计划
长处
- 升高了利用革新的老本,通过 html entry 的形式引入子利用;
- 提供了齐备的沙箱计划,包含 js 沙箱和 css 沙箱;
- 反对动态资源预加载能力。
毛病
- 适配老本较高,包含工程化、生命周期、动态资源门路、路由等方面的适配;
- css 沙箱的严格隔离可能引发问题,js 沙箱在某些场景下执行性能降落;
- 无奈同时激活多个子利用,不反对子利用保活;
- 不反对 vite 等 esmodule 脚本运行。
-
micro-app 计划
长处
- 应用 webcomponent 加载子利用,更优雅;
- 复用通过大量我的项目验证过的 qiankun 沙箱机制,进步了框架的可靠性;
- 反对子利用保活;
- 升高了子利用革新的老本,提供了动态资源预加载能力。
毛病
- 接入老本尽管升高,但路由仍然存在依赖;
- 多利用激活后无奈放弃各子利用的路由状态,刷新后全副失落;
- css 沙箱无奈齐全隔离,js 沙箱做全局变量查找缓存,性能有所优化;
- 反对 vite 运行,但必须应用 plugin 革新子利用,且 js 代码没方法做沙箱隔离;
- 对于不反对 webcomponent 的浏览器没有做降级解决。
-
EMP 计划
长处
- webpack 联邦编译能够保障所有子利用依赖解耦;
- 反对利用间去中心化的调用、共享模块;
- 反对模块近程 ts 反对。
毛病
- 对 webpack 强依赖,对于老旧我的项目不敌对;
- 没有无效的 css 沙箱和 js 沙箱,须要靠用户盲目;
- 子利用保活、多利用激活无奈实现;
- 主、子利用的路由可能发生冲突。
-
无界计划
长处
- 基于 webcomponent 容器和 iframe 沙箱,充沛解决了适配老本、款式隔离、运行性能、页面白屏、子利用通信、子利用保活、多利用激活、vite 框架反对、利用共享等问题。
毛病
- 在继承了 iframe 长处的同时,毛病仍旧还是存在