ๅพฎๅ็ซฏๆทฑๅบฆๅฏนๆฏ๏ผQiankun 3.0 vs Wujie 1.0
Source: Juejin Frontend Hottest
Qiankun vs Wujie๏ผๅพฎๅ็ซฏๆกๆถๆทฑๅบฆๅฏนๆฏ
ๅบไบ Qiankun 3.0 ๅ Wujie 1.0.22 ๆบ็ ๆทฑๅบฆๅๆ๏ผไปๆถๆ่ฎพ่ฎกใ้็ฆปๆนๆกใ่ตๆบๅ ่ฝฝใ้ไฟกๆบๅถใ่ทฏ็ฑๅค็ใ้ขๅ ่ฝฝ็ญ็ฅใๆไปถ็ณป็ป็ญ็ปดๅบฆ่ฟ่กๅ จ้ขๅฏนๆฏ๏ผๅฉไฝ ๅๅบๆไฝณๆๆฏ้ๅใ
ไธใ่ฎพ่ฎกๅฒๅญฆ
1.1 ๆถๆ็ๅฟต
| ็ปดๅบฆ | Qiankun | Wujie |
|---|---|---|
| ๅบ็กๆถๆ | ๅบไบ single-spa ๅฐ่ฃ | ๅๅๅๅฎนๅจๆถๆ |
| ้็ฆปๆ่ทฏ | Proxy ไปฃ็ๆจกๆ้็ฆป | ๆต่งๅจๅ็้็ฆป |
| ๆ ธๅฟๆๆฏ | Proxy + with + Membrane | iframe + Shadow DOM + Proxy |
| ่ฎพ่ฎก็ฎๆ | ๅผ็ฎฑๅณ็จใ็ๆๅฎๅ | ๆ่ด้็ฆปใไฝไพตๅ ฅ |
| ๅ ็ปๆ | monorepo๏ผsandbox/loader/shared๏ผ | ๅๅ |
1.2 ๆถๆๅพๅฏนๆฏ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Qiankun ๆถๆ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ ไธปๅบ็จ Window โ โ
โ โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โ โ
โ โ โ ๅญๅบ็จ A โ โ ๅญๅบ็จ B โ โ ๅญๅบ็จ C โ โ โ
โ โ โ โ โ โ โ โ โ โ
โ โ โ โโโโโโโโโโโ โ โ โโโโโโโโโโโ โ โ โโโโโโโโโโโ โ โ โ
โ โ โ โ Proxy โ โ โ โ Proxy โ โ โ โ Proxy โ โ โ โ
โ โ โ โ Sandbox โ โ โ โ Sandbox โ โ โ โ Sandbox โ โ โ โ
โ โ โ โโโโโโโโโโโ โ โ โโโโโโโโโโโ โ โ โโโโโโโโโโโ โ โ โ
โ โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ โ
โ single-spa โ
โ (่ทฏ็ฑๅซๆ + ็ๅฝๅจๆ็ฎก็) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Wujie ๆถๆ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ wujie-app (Web Component) โ โ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
โ โ โ Shadow DOM โ CSS ๅฎๅ
จ้็ฆป โ โ โ
โ โ โ ๅญๅบ็จ HTML/CSS ๆธฒๆ โ โ โ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Proxy ไปฃ็ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ ้่ iframe โ JS ๅ็้็ฆป โ โ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
โ โ โ ๅญๅบ็จ JS ่ฟ่ก โ โ โ
โ โ โ ็ฌ็ซ window / document / location โ โ โ
โ โ โ DOM ๆไฝ้่ฟ Proxy ไปฃ็ๅฐ Shadow DOM โ โ โ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
ไบใJS ๆฒ็ฎฑๆบๅถ
2.1 Qiankun๏ผProxy + Membrane + Compartment
Qiankun 3.0 ้็จไธๅฑๆถๆๅฎ็ฐ JS ้็ฆป๏ผ
// 1. Membrane ๅฑ๏ผProxy ไปฃ็ๆฆๆชๅฑๆง่ฎฟ้ฎ
const handler: ProxyHandler<Window> = {
get(target, p) {
if (p in endowments) return endowments[p].value;
if (modifications.has(p)) return modifications.get(p);
return Reflect.get(target, p);
},
set(target, p, value) {
if (locked) return false; // ๆฒ็ฎฑ้ๅฎๆถ็ฆๆญขไฟฎๆน
modifications.set(p, value);
return true;
},
};
// 2. Compartment ๅฑ๏ผwith ่ฏญๅฅ็ปๅฎไฝ็จๅ
;(function(){
with(this){
const {console,document,...} = this; // ไผๅๅธธ็จๅ้
// ๅญๅบ็จไปฃ็
}
}).bind(proxyWindow)();
// 3. Patchers ๅฑ๏ผๅฏไฝ็จ็ฎก็
patchWindowListener(sandbox); // ไบไปถ็ๅฌ
patchInterval(sandbox); // ๅฎๆถๅจ
patchHistoryListener(sandbox); // History ็ๅฌ
็น็น๏ผ
- modifications Map ่ฎฐๅฝๆๆไฟฎๆน๏ผๆฏๆๅฟซ็ งๆขๅค
- ้ๅฎๆบๅถ๏ผinactive ๆถ็ฆๆญขไฟฎๆน
- ๅฏไฝ็จ่กฅไธ๏ผๆๅจ็ฎก็ไบไปถใๅฎๆถๅจ็ญ
2.2 Wujie๏ผiframe ๅ็้็ฆป + Proxy ไปฃ็
Wujie ๅฉ็จ iframe ็ๅ็้็ฆป่ฝๅ๏ผ
// 1. ๅๅปบๅๅ iframe๏ผ้ฟๅ
่ทจๅ๏ผ
const iframe = document.createElement("iframe");
iframe.src = mainHostPath; // ๅๅ
iframe.style.display = "none";
// 2. ้ปๆญข iframe ๅ ่ฝฝไธปๅบ็จๅ
ๅฎน
iframeWindow.stop();
// 3. IIFE ๅ
่ฃ
่ๆฌ๏ผๆฟๆขๅ
จๅฑๅ้
(function(window, self, global, location) {
// ๅญๅบ็จไปฃ็
window.foo = 'bar'; // ๅฎ้
ๆไฝ proxy
}).bind(window.__WUJIE.proxy)(
window.__WUJIE.proxy,
window.__WUJIE.proxy,
window.__WUJIE.proxy,
window.__WUJIE.proxyLocation,
);
// 4. Proxy ไปฃ็ document ๆไฝๅฐ Shadow DOM
const proxyDocument = new Proxy({}, {
get(_, propKey) {
if (propKey === "getElementById") {
return (id) => shadowRoot.querySelector(`[id="${id}"]`);
}
// ...
},
});
็น็น๏ผ
- iframe ๆไพๅฎๆด็ฌ็ซ็ window ๅฏน่ฑก
- ๅ็ JS ้็ฆป๏ผๆ ้ๆจกๆ
- ไบไปถใๅฎๆถๅจ่ชๅจ้็ฆป๏ผๆ ้ๆๅจๆธ ็
2.3 ้็ฆป่ฝๅๅฏนๆฏ
| ๅบๆฏ | Qiankun | Wujie | ่ฏดๆ |
|---|---|---|---|
| ๅ จๅฑๅ้ๆฑกๆ | โ Proxy ๆฆๆช | โ ๅ็้็ฆป | ้ฝ่ฝๅค็ |
| ๅๅ้พๆฑกๆ | โ ๏ธ ้้ขๅคๅค็ | โ ๅ็้็ฆป | Array.prototype.xxx |
| eval/new Function | โ ๏ธ ๅฏ่ฝ้้ธ | โ ๅ็้็ฆป | ๅจๆไปฃ็ ๆง่ก |
| ๅฎๆถๅจๆธ ็ | ้ patch | ่ชๅจๆธ ็ | setInterval/setTimeout |
| ไบไปถ็ๅฌๆธ ็ | ้ patch | ่ชๅจๆธ ็ | addEventListener |
| localStorage | ๅ ฑไบซ | ๅฏ้ ็ฝฎ้็ฆป | ้่ฟๆไปถๅฎ็ฐ |
| Cookie | ๅ ฑไบซ | ๅ ฑไบซ | ๅๅ้ๅถ |
ไธใCSS ้็ฆปๆบๅถ
3.1 Qiankun๏ผScoped CSS / Shadow DOM
// ๆนๅผไธ๏ผScoped CSS๏ผ้ป่ฎค๏ผ
// ๅๅง
.container { color: red; }
// ่ฝฌๆขๅ
div[data-qiankun="app-name"] .container { color: red; }
// ๆนๅผไบ๏ผShadow DOM๏ผๅฎ้ชๆง๏ผ
start({ sandbox: { experimentalStyleIsolation: true } });
้ฎ้ข๏ผ
- Scoped CSS ๅฏ่ฝๆ้ๆฉๅจๆ้้ฎ้ข
- Shadow DOM ไธๅผน็ชๆ ทๅผ้่ฆ็นๆฎๅค็
3.2 Wujie๏ผShadow DOM + CSS Loader
// 1. ๅๅปบ Web Component
class WujieApp extends HTMLElement {
connectedCallback() {
this.attachShadow({ mode: "open" });
}
}
customElements.define("wujie-app", WujieApp);
// 2. ๆธฒๆๅฐ Shadow DOM
shadowRoot.innerHTML = template;
// 3. :root ่ฝฌๆขไธบ :host
const cssSelectorMap = { ":root": ":host" };
// 4. @font-face ๆๅๅฐๅค้จ๏ผShadow DOM ๅ
ๅญไฝไธ็ๆ๏ผ
if (cssRule.type === CSSRule.FONT_FACE_RULE) {
fontCssRules.push(cssRuleText);
}
shadowRoot.host.appendChild(fontStyleSheetElement);
// 5. CSS ็ธๅฏน่ทฏๅพๅค็
code.replace(/url\((['"]?)(.*)(\1)\)/g, (_, pre, url, post) => {
return `url(${pre}${getAbsolutePath(url, baseUrl)}${post})`;
});
็น็น๏ผ
- ๅ็ Shadow DOM ้็ฆป
- ่ชๅจๅค็ :root โ :host
- @font-face ่ชๅจๆๅ
- CSS ็ธๅฏน่ทฏๅพ่ชๅจ่ฝฌๆข
3.3 CSS ้็ฆปๅฏนๆฏ
| ็นๆง | Qiankun Scoped | Qiankun Shadow | Wujie Shadow |
|---|---|---|---|
| ้็ฆป็จๅบฆ | ไธญ | ้ซ | ้ซ |
| ๅ ผๅฎนๆง | ๅฅฝ | ไธ่ฌ | ไธ่ฌ |
| ๅผน็ชๆ ทๅผ | โ ๆญฃๅธธ | โ ้ๅค็ | โ ้ๅค็ |
| ๅ จๅฑๆ ทๅผๆณๆผ | ๅฏ่ฝ | ไธไผ | ไธไผ |
| :root ๆฏๆ | โ | โ ้่ฝฌๆข | โ ่ชๅจ่ฝฌๆข |
| @font-face | โ | โ ้ๅค็ | โ ่ชๅจๅค็ |
ๅใ่ตๆบๅ ่ฝฝๆบๅถ
4.1 Qiankun๏ผๆตๅผๅ ่ฝฝ + HTML Entry
// 1. Fetch ๅขๅผบ
const enhancedFetch = makeFetchCacheable(
makeFetchRetryable(
makeFetchThrowable(fetch)
)
);
// 2. ๆตๅผๅ ่ฝฝ
res.body
.pipeThrough(new TextDecoderStream())
.pipeThrough(createTagTransformStream([
{ tag: '<head>', alt: '<qiankun-head>' }, // ้ฟๅ
ๆฑกๆไธปๅบ็จ head
]))
.pipeTo(new WritableDOMStream(container, nodeTransformer));
// 3. ่ๆฌๆฒ็ฎฑๅ
่ฃ
const wrappedCode = sandbox.makeEvaluateFactory(code, entry);
// 4. defer ่ๆฌ้ๅไฟ่ฏ้กบๅบๆง่ก
็น็น๏ผ
- ่พนไธ่ฝฝ่พน่งฃๆ๏ผ้ฆๅฑๆดๅฟซ
- head ๆ ็ญพ่ฝฌๆข้ฟๅ ๆฑกๆ
- Fetch ็ผๅญ + ้่ฏๆบๅถ
- defer ่ๆฌ้กบๅบไฟ่ฏ
4.2 Wujie๏ผimportHTML + ่ๆฌๅ็ฑป
// 1. ๅ ่ฝฝ HTML
const { template, getExternalScripts, getExternalStyleSheets } =
await importHTML({ url, html, opts });
// 2. ่ๆฌๅ็ฑปๆง่ก
const syncScriptResultList = []; // ๅๆญฅ่ๆฌ
const asyncScriptResultList = []; // ๅผๆญฅ่ๆฌ
const deferScriptResultList = []; // defer ่ๆฌ
// 3. ๆๅปบๆง่ก้ๅ
syncScriptResultList.concat(deferScriptResultList).forEach((script) => {
this.execQueue.push(() => insertScriptToIframe(script, iframeWindow));
});
// 4. ๅผๆญฅ่ๆฌไธๅ
ฅ้ๅ
asyncScriptResultList.forEach((script) => {
script.contentPromise.then((content) => {
insertScriptToIframe({ ...script, content }, iframeWindow);
});
});
// 5. ่งฆๅ็ๅฝๅจๆไบไปถ
this.execQueue.push(() => eventTrigger(iframeWindow.document, "DOMContentLoaded"));
this.execQueue.push(() => eventTrigger(iframeWindow, "load"));
็น็น๏ผ
- ่ๆฌๅ็ฑปๅค็๏ผsync/async/defer๏ผ
- ๆง่ก้ๅไฟ่ฏ้กบๅบ
- ๆญฃ็กฎ่งฆๅ DOMContentLoaded/load ไบไปถ
ไบใ้ไฟกๆบๅถ
5.1 Qiankun๏ผProps + ๅ จๅฑ็ถๆ
// 1. Props ไผ ้
registerMicroApps([{
name: 'app',
props: { user, token, onLogout, utils: { request, storage } },
}]);
// ๅญๅบ็จๆฅๆถ
export async function mount(props) {
const { user, token, onLogout, utils } = props;
}
// 2. ๅ
จๅฑ็ถๆ๏ผ2.x๏ผ3.0 ๅทฒ็งป้ค๏ผ
const actions = initGlobalState({ user: null });
actions.onGlobalStateChange((state, prev) => {});
actions.setGlobalState({ user: newUser });
// 3. ่ชๅฎไนไบไปถ
window.dispatchEvent(new CustomEvent('micro-app-event', { detail }));
5.2 Wujie๏ผEventBus + Props
// 1. ๅ
จๅฑไบไปถ Map๏ผๆฏๆ่ทจๅบ็จ้ไฟก๏ผ
export const appEventObjMap = new Map<String, EventObj>();
// 2. EventBus ๅฎ็ฐ
class EventBus {
$emit(event, ...args) {
// ้ๅๆๆๅบ็จ็ไบไปถๅฏน่ฑก
appEventObjMap.forEach((eventObj) => {
if (eventObj[event]) {
eventObj[event].forEach((fn) => fn(...args));
}
});
}
}
// 3. ไธปๅบ็จไฝฟ็จ
import { bus } from 'wujie';
bus.$emit('theme-change', { theme: 'dark' });
bus.$on('user-logout', () => router.push('/login'));
// 4. ๅญๅบ็จไฝฟ็จ
window.$wujie.bus.$on('theme-change', ({ theme }) => {});
window.$wujie.bus.$emit('user-logout');
// 5. Props ไผ ้
startApp({ props: { user, api: { getUserInfo, logout } } });
const { props } = window.$wujie;
5.3 ้ไฟกๅฏนๆฏ
| ็นๆง | Qiankun | Wujie |
|---|---|---|
| Props ไผ ้ | โ | โ |
| ไบไปถๆป็บฟ | ้่ชๅปบ | โ ๅ ็ฝฎ |
| ๅ จๅฑ็ถๆ | โ initGlobalState๏ผ2.x๏ผ | ้่ชๅปบ |
| ่ทจๅบ็จ้ไฟก | ้่ฟไธปๅบ็จไธญ่ฝฌ | โ ็ดๆฅ้ไฟก |
| ๅตๅฅๅบ็จ้ไฟก | ้ๅค็ | โ ่ชๅจๆฏๆ |
ๅ ญใ่ทฏ็ฑๅค็
6.1 Qiankun๏ผsingle-spa ่ทฏ็ฑๅซๆ
// 1. History API ๅซๆ
window.history.pushState = function(...args) {
const result = originalPushState.apply(this, args);
reroute(); // ่งฆๅ่ทฏ็ฑๅๅๆฃๆฅ
return result;
};
// 2. ็ๅฌไบไปถ
window.addEventListener('popstate', reroute);
window.addEventListener('hashchange', reroute);
// 3. activeRule ๅน้
registerMicroApps([{
activeRule: '/react', // ๅญ็ฌฆไธฒ
activeRule: ['/react', '/react-app'], // ๆฐ็ป
activeRule: (location) => location.pathname.startsWith('/react'), // ๅฝๆฐ
}]);
// 4. ๅญๅบ็จ้่ฆ่ฎพ็ฝฎ basename
<BrowserRouter basename={window.__POWERED_BY_QIANKUN__ ? '/react' : '/'}>
6.2 Wujie๏ผURL Query ๅๆญฅ
// 1. ๅญๅบ็จ่ทฏ็ฑๅญๅ
ฅไธปๅบ็จ URL
// ไธปๅบ็จ: https://main.com/home?vue3=%2Fuser%2F123
// ๅญๅบ็จ: /user/123
// 2. History ๅซๆๅๆญฅ
history.pushState = function(data, title, url) {
rawHistoryPushState.call(history, data, title, mainUrl);
syncUrlToWindow(iframeWindow); // ๅๆญฅๅฐไธปๅบ็จ URL
};
// 3. ็ญ่ทฏๅพไผๅ
startApp({
sync: true,
prefix: { 'u': '/user' }, // /user/123 โ {u}/123
});
// 4. ๅทๆฐๆขๅค
const syncUrl = getSyncUrl(id, prefix); // ไป URL ่ทๅๅญๅบ็จ่ทฏ็ฑ
6.3 ่ทฏ็ฑๅฏนๆฏ
| ็นๆง | Qiankun | Wujie |
|---|---|---|
| ่ทฏ็ฑๆจกๅผ | hash/history | hash/history |
| URL ๅๆญฅ | ้้ ็ฝฎ | โ sync ๆจกๅผ |
| ่ทฏ็ฑ้็ฆป | ๅ ฑไบซ history | ็ฌ็ซ history |
| ๅทๆฐๆขๅค | ้ๅค็ | โ ่ชๅจๆขๅค |
| ็ญ่ทฏๅพไผๅ | โ | โ prefix ้ ็ฝฎ |
| ๅญๅบ็จๆน้ | ้่ฎพ็ฝฎ basename | ๆ ้ๆน้ |
ไธใ้ขๅ ่ฝฝ็ญ็ฅ
7.1 Qiankun๏ผๅค็ญ็ฅ้ขๅ ่ฝฝ
// 1. ้
็ฝฎๆนๅผ
start({ prefetch: true }); // ้ฆๅฑๅ้ขๅ ่ฝฝๆๆ
start({ prefetch: 'all' }); // ็ซๅณ้ขๅ ่ฝฝๆๆ
start({ prefetch: ['react-app'] }); // ๆๅฎๅบ็จ
start({
prefetch: (apps) => ({
criticalAppNames: ['react-app'], // ๅ
ณ้ฎๅบ็จ็ซๅณๅ ่ฝฝ
minorAppNames: ['vue-app'], // ๆฌก่ฆๅบ็จ็ฉบ้ฒๆถๅ ่ฝฝ
}),
});
// 2. ็ฉบ้ฒๆถๅ ่ฝฝ
requestIdleCallback(async () => {
const { getExternalScripts, getExternalStyleSheets } = await importEntry(entry);
requestIdleCallback(getExternalStyleSheets);
requestIdleCallback(getExternalScripts);
});
// 3. ๅบไบ็ฝ็ป็ถๅต
if (connection.effectiveType === 'slow-2g') {
return { criticalAppNames: [], minorAppNames: [] };
}
7.2 Wujie๏ผpreloadApp
// 1. ้ขๅ ่ฝฝ
import { preloadApp } from 'wujie';
preloadApp({ name: 'vue3', url: 'http://localhost:7300/' });
// 2. ้ขๆง่ก๏ผๅๅปบๆฒ็ฎฑไฝไธๆธฒๆ๏ผ
preloadApp({ name: 'vue3', url: '...', exec: true });
// 3. ไฟๆดปๆจกๅผ๏ผ็ถๆไฟ็๏ผ
startApp({ alive: true }); // ๅๆขๆถไธ้ๆฏ๏ผ็ดๆฅๆฟๆดป
7.3 ้ขๅ ่ฝฝๅฏนๆฏ
| ็นๆง | Qiankun | Wujie |
|---|---|---|
| ้ขๅ ่ฝฝ่ตๆบ | โ | โ |
| ้ขๆง่ก | โ | โ exec ๆจกๅผ |
| ไฟๆดปๆจกๅผ | โ | โ alive ๆจกๅผ |
| ็ฉบ้ฒๅ ่ฝฝ | โ requestIdleCallback | โ |
| ่ชๅฎไน็ญ็ฅ | โ ๅฝๆฐ้ ็ฝฎ | โ |
| ็ฝ็ปๆ็ฅ | ๅฏๅฎ็ฐ | โ |
ๅ ซใๆไปถ/ๆฉๅฑ็ณป็ป
8.1 Qiankun๏ผ็ๅฝๅจๆ้ฉๅญ
registerMicroApps(apps, {
beforeLoad: [(app) => console.log('beforeLoad', app.name)],
beforeMount: [(app) => console.log('beforeMount', app.name)],
afterMount: [(app) => console.log('afterMount', app.name)],
beforeUnmount: [(app) => console.log('beforeUnmount', app.name)],
afterUnmount: [(app) => console.log('afterUnmount', app.name)],
});
8.2 Wujie๏ผๅฎๆดๆไปถ็ณป็ป
startApp({
plugins: [{
// HTML ๅค็
htmlLoader: (code) => code,
// JS ๅค็
jsExcludes: [/google-analytics/], // ๆ้ค
jsIgnores: [/ad\.js/], // ๅฟฝ็ฅๆง่ก
jsBeforeLoaders: [{ content: 'window.ENV = "prod"' }],
jsLoader: (code, url) => code.replace(/api\.dev/g, 'api.prod'),
jsAfterLoaders: [{ src: 'https://cdn.com/init.js' }],
// CSS ๅค็
cssExcludes: [],
cssBeforeLoaders: [{ content: ':root { --theme: dark; }' }],
cssLoader: (code, url) => code,
cssAfterLoaders: [],
// ไบไปถ้ฉๅญ
windowAddEventListenerHook: (win, type, handler) => {},
documentAddEventListenerHook: (win, type, handler) => {},
// DOM ้ฉๅญ
appendOrInsertElementHook: (element, iframeWindow) => {},
patchElementHook: (element, iframeWindow) => {},
// ๅฑๆง่ฆ็
windowPropertyOverride: (iframeWindow) => {
iframeWindow.localStorage = customStorage;
},
documentPropertyOverride: (iframeWindow) => {},
}],
});
8.3 ๆฉๅฑ่ฝๅๅฏนๆฏ
| ็นๆง | Qiankun | Wujie |
|---|---|---|
| ็ๅฝๅจๆ้ฉๅญ | โ | โ |
| JS Loader | โ | โ |
| CSS Loader | โ | โ |
| ่ตๆบๆ้ค/ๅฟฝ็ฅ | โ | โ |
| ๅ็ฝฎ/ๅ็ฝฎ่ๆฌ | โ | โ |
| ไบไปถๆฆๆช | โ | โ |
| DOM ๆฆๆช | โ | โ |
| ๅฑๆง่ฆ็ | โ | โ |
ไนใ็ๅฝๅจๆ
9.1 Qiankun ็ๅฝๅจๆ
beforeLoad โ bootstrap โ beforeMount โ mount โ afterMount
โ
beforeUnmount โ unmount โ afterUnmount
ๅญๅบ็จๅฟ ้กปๅฏผๅบ๏ผ
export async function bootstrap() {}
export async function mount(props) {}
export async function unmount(props) {}
9.2 Wujie ็ๅฝๅจๆ
beforeLoad โ active โ start โ beforeMount โ mount โ afterMount
โ
beforeUnmount โ unmount โ afterUnmount
ๅญๅบ็จๅฏ้ๅฏผๅบ๏ผ
window.__WUJIE_MOUNT = () => {};
window.__WUJIE_UNMOUNT = () => {};
9.3 ็ๅฝๅจๆๅฏนๆฏ
| ็นๆง | Qiankun | Wujie |
|---|---|---|
| ๅฟ ้กปๅฏผๅบ | โ ๅฟ ้กป | โ ๅฏ้ |
| ๆน้ ๆๆฌ | ไธญ | ไฝ |
| ็ฌ็ซ่ฟ่ก | ้ๅคๆญ __POWERED_BY_QIANKUN__ | ่ชๅจๅ ผๅฎน |
| ็ๅฝๅจๆๆฐ้ | 5 ไธช | 6 ไธช |
ๅใๆง่ฝๅฏนๆฏ
| ็ปดๅบฆ | Qiankun | Wujie |
|---|---|---|
| ้ฆๆฌกๅ ่ฝฝ | ๅฟซ | ็จๆ ข๏ผๅๅปบ iframe๏ผ |
| ๅๆข้ๅบฆ | ๅฟซ | ๅฟซ๏ผไฟๆดปๆจกๅผๆดๅฟซ๏ผ |
| ๅ ๅญๅ ็จ | ไฝ | ไธญ๏ผiframe ๅผ้๏ผ |
| ๆฒ็ฎฑๅๅปบ | ๅฟซ๏ผProxy๏ผ | ็จๆ ข๏ผiframe๏ผ |
| ๆ ทๅผ้็ฆปๅผ้ | ไฝ๏ผScoped๏ผ/ ไธญ๏ผShadow๏ผ | ไธญ๏ผShadow๏ผ |
ๅไธใๅ ผๅฎนๆง
| ็นๆง | Qiankun | Wujie |
|---|---|---|
| IE ๆฏๆ | โ ้ Proxy polyfill | โ |
| ๆไฝๆต่งๅจ | Chrome 49+ | Chrome 53+ |
| Web Components | ๅฏ้ | ๅฟ ้๏ผๆ้็บง๏ผ |
| Proxy | ๅฟ ้ | ๅฟ ้ |
ๅไบใ้ๅๅปบ่ฎฎ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ้ๅๅณ็ญๆ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ ้่ฆๆ่ด JS ้็ฆป๏ผ โ
โ โโโ ๆฏ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโถ Wujie โ
โ โโโ ๅฆ โโโถ ็ปง็ปญๅคๆญ โ
โ โ
โ ๅญๅบ็จๆน้ ๆๆฌๆๆ๏ผ โ
โ โโโ ๆฏ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโถ Wujie โ
โ โโโ ๅฆ โโโถ ็ปง็ปญๅคๆญ โ
โ โ
โ ้่ฆไฟๆดปๆจกๅผ๏ผ็ถๆไฟ็๏ผ๏ผ โ
โ โโโ ๆฏ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโถ Wujie โ
โ โโโ ๅฆ โโโถ ็ปง็ปญๅคๆญ โ
โ โ
โ ไฝฟ็จ umi ๆกๆถ๏ผ โ
โ โโโ ๆฏ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโถ Qiankun โ
โ โโโ ๅฆ โโโถ ็ปง็ปญๅคๆญ โ
โ โ
โ ้่ฆๆ็็ๆๅ็คพๅบๆฏๆ๏ผ โ
โ โโโ ๆฏ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโถ Qiankun โ
โ โโโ ๅฆ โโโถ ็ปง็ปญๅคๆญ โ
โ โ
โ ้่ฆไธฐๅฏ็ๆไปถ่ฝๅ๏ผ โ
โ โโโ ๆฏ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโถ Wujie โ
โ โโโ ๅฆ โโโถ ้ฝๅฏไปฅ โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
้ๆฉ Qiankun ็ๅบๆฏ
- umi ้กน็ฎ๏ผ้่ฆๆทฑๅบฆ้ๆ
- ๅข้็ๆ single-spa ็ๆ
- ๅฏน้็ฆป่ฆๆฑไธๆ่ด๏ผๆฅๅ Proxy ๆนๆก
- ้่ฆๆ็็จณๅฎ็่งฃๅณๆนๆก
- ๅญๅบ็จๅฏไปฅ้ ๅๆน้
้ๆฉ Wujie ็ๅบๆฏ
- ้่ฆๆ่ด็ JS ้็ฆป่ฝๅ
- ๅญๅบ็จๆน้ ๆๆฌ่ฆๆฑไฝ
- ้่ฆไฟๆดปๆจกๅผ๏ผ้ข็นๅๆขๅบๆฏ๏ผ
- ้่ฆไธฐๅฏ็ๆไปถๆฉๅฑ่ฝๅ
- ้่ฆ่ทฏ็ฑๅๆญฅๅฐ URL
ๅไธใๆป็ป
| ็ปดๅบฆ | Qiankun | Wujie | ่ๅบ |
|---|---|---|---|
| JS ้็ฆป | Proxy ๆจกๆ | iframe ๅ็ | Wujie |
| CSS ้็ฆป | Scoped/Shadow | Shadow | ๅนณๆ |
| ๆน้ ๆๆฌ | ไธญ | ไฝ | Wujie |
| ็ๆๆ็ๅบฆ | ้ซ | ไธญ | Qiankun |
| ๆไปถ่ฝๅ | ๅผฑ | ๅผบ | Wujie |
| ้ขๅ ่ฝฝ | ไธฐๅฏ | ๅบ็ก | Qiankun |
| ไฟๆดปๆจกๅผ | โ | โ | Wujie |
| ่ทฏ็ฑๅๆญฅ | ้ๅค็ | ๅ ็ฝฎ | Wujie |
| ๅ ๅญๅ ็จ | ไฝ | ไธญ | Qiankun |
| ็คพๅบๆฏๆ | ๅผบ | ไธญ | Qiankun |
ๆ็ป็ป่ฎบ๏ผ
- Qiankun๏ผๆ็็จณๅฎ๏ผ็ๆๅฎๅ๏ผๆฏๅบไบ single-spa ็ไบๅฎๆ ๅ๏ผ้ๅๅฏน็จณๅฎๆง่ฆๆฑ้ซใๆ umi ๆๆฏๆ ็ๅข้
- Wujie๏ผ้็ฆปๅฝปๅบ๏ผๆน้ ๆๆฌไฝ๏ผๅๆฐ็ๅๅฎนๅจๆถๆ๏ผ้ๅๅฏน้็ฆป่ฆๆฑ้ซใ้่ฆไฟๆดปๆจกๅผใๅญๅบ็จๆน้ ๅ้็ๅบๆฏ
ไธคไธชๆกๆถๅๆๅ็ง๏ผ้ๅๆถ้่ฆๆ นๆฎ้กน็ฎๅฎ้ ๆ ๅต๏ผๆ่กก้็ฆป่ฝๅใๆน้ ๆๆฌใๅข้็ๆๅบฆใ็ๆๆฏๆ็ญๅ ็ด ็ปผๅ่่ใ
๐ฆ ๆบ็ ๅ่๏ผ
- Qiankun GitHub - ๅบไบ v3.0 ๅๆ
- Wujie GitHub - ๅบไบ v1.0.22 ๅๆ
๐ ็ธๅ ณไธๆ ๏ผ