ๅพฎๅ‰็ซฏๆทฑๅบฆๅฏนๆฏ”๏ผšQiankun 3.0 vs Wujie 1.0

Source: Juejin Frontend Hottest

Qiankun vs Wujie๏ผšๅพฎๅ‰็ซฏๆก†ๆžถๆทฑๅบฆๅฏนๆฏ”

ๅŸบไบŽ Qiankun 3.0 ๅ’Œ Wujie 1.0.22 ๆบ็ ๆทฑๅบฆๅˆ†ๆž๏ผŒไปŽๆžถๆž„่ฎพ่ฎกใ€้š”็ฆปๆ–นๆกˆใ€่ต„ๆบๅŠ ่ฝฝใ€้€šไฟกๆœบๅˆถใ€่ทฏ็”ฑๅค„็†ใ€้ข„ๅŠ ่ฝฝ็ญ–็•ฅใ€ๆ’ไปถ็ณป็ปŸ็ญ‰็ปดๅบฆ่ฟ›่กŒๅ…จ้ขๅฏนๆฏ”๏ผŒๅŠฉไฝ ๅšๅ‡บๆœ€ไฝณๆŠ€ๆœฏ้€‰ๅž‹ใ€‚

ไธ€ใ€่ฎพ่ฎกๅ“ฒๅญฆ

1.1 ๆžถๆž„็†ๅฟต

็ปดๅบฆQiankunWujie
ๅŸบ็ก€ๆžถๆž„ๅŸบไบŽ single-spa ๅฐ่ฃ…ๅŽŸๅˆ›ๅŒๅฎนๅ™จๆžถๆž„
้š”็ฆปๆ€่ทฏProxy ไปฃ็†ๆจกๆ‹Ÿ้š”็ฆปๆต่งˆๅ™จๅŽŸ็”Ÿ้š”็ฆป
ๆ ธๅฟƒๆŠ€ๆœฏProxy + with + Membraneiframe + 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 ้š”็ฆป่ƒฝๅŠ›ๅฏนๆฏ”

ๅœบๆ™ฏQiankunWujie่ฏดๆ˜Ž
ๅ…จๅฑ€ๅ˜้‡ๆฑกๆŸ“โœ… 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 ScopedQiankun ShadowWujie 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 ้€šไฟกๅฏนๆฏ”

็‰นๆ€งQiankunWujie
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 ่ทฏ็”ฑๅฏนๆฏ”

็‰นๆ€งQiankunWujie
่ทฏ็”ฑๆจกๅผhash/historyhash/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 ้ข„ๅŠ ่ฝฝๅฏนๆฏ”

็‰นๆ€งQiankunWujie
้ข„ๅŠ ่ฝฝ่ต„ๆบโœ…โœ…
้ข„ๆ‰ง่กŒโŒโœ… 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 ๆ‰ฉๅฑ•่ƒฝๅŠ›ๅฏนๆฏ”

็‰นๆ€งQiankunWujie
็”Ÿๅ‘ฝๅ‘จๆœŸ้’ฉๅญโœ…โœ…
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 ็”Ÿๅ‘ฝๅ‘จๆœŸๅฏนๆฏ”

็‰นๆ€งQiankunWujie
ๅฟ…้กปๅฏผๅ‡บโœ… ๅฟ…้กปโŒ ๅฏ้€‰
ๆ”น้€ ๆˆๆœฌไธญไฝŽ
็‹ฌ็ซ‹่ฟ่กŒ้œ€ๅˆคๆ–ญ __POWERED_BY_QIANKUN__่‡ชๅŠจๅ…ผๅฎน
็”Ÿๅ‘ฝๅ‘จๆœŸๆ•ฐ้‡5 ไธช6 ไธช

ๅใ€ๆ€ง่ƒฝๅฏนๆฏ”

็ปดๅบฆQiankunWujie
้ฆ–ๆฌกๅŠ ่ฝฝๅฟซ็จๆ…ข๏ผˆๅˆ›ๅปบ iframe๏ผ‰
ๅˆ‡ๆข้€Ÿๅบฆๅฟซๅฟซ๏ผˆไฟๆดปๆจกๅผๆ›ดๅฟซ๏ผ‰
ๅ†…ๅญ˜ๅ ็”จไฝŽไธญ๏ผˆiframe ๅผ€้”€๏ผ‰
ๆฒ™็ฎฑๅˆ›ๅปบๅฟซ๏ผˆProxy๏ผ‰็จๆ…ข๏ผˆiframe๏ผ‰
ๆ ทๅผ้š”็ฆปๅผ€้”€ไฝŽ๏ผˆScoped๏ผ‰/ ไธญ๏ผˆShadow๏ผ‰ไธญ๏ผˆShadow๏ผ‰

ๅไธ€ใ€ๅ…ผๅฎนๆ€ง

็‰นๆ€งQiankunWujie
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

ๅไธ‰ใ€ๆ€ป็ป“

็ปดๅบฆQiankunWujie่ƒœๅ‡บ
JS ้š”็ฆปProxy ๆจกๆ‹Ÿiframe ๅŽŸ็”ŸWujie
CSS ้š”็ฆปScoped/ShadowShadowๅนณๆ‰‹
ๆ”น้€ ๆˆๆœฌไธญไฝŽWujie
็”Ÿๆ€ๆˆ็†Ÿๅบฆ้ซ˜ไธญQiankun
ๆ’ไปถ่ƒฝๅŠ›ๅผฑๅผบWujie
้ข„ๅŠ ่ฝฝไธฐๅฏŒๅŸบ็ก€Qiankun
ไฟๆดปๆจกๅผโŒโœ…Wujie
่ทฏ็”ฑๅŒๆญฅ้œ€ๅค„็†ๅ†…็ฝฎWujie
ๅ†…ๅญ˜ๅ ็”จไฝŽไธญQiankun
็คพๅŒบๆ”ฏๆŒๅผบไธญQiankun

ๆœ€็ปˆ็ป“่ฎบ๏ผš

  • Qiankun๏ผšๆˆ็†Ÿ็จณๅฎš๏ผŒ็”Ÿๆ€ๅฎŒๅ–„๏ผŒๆ˜ฏๅŸบไบŽ single-spa ็š„ไบ‹ๅฎžๆ ‡ๅ‡†๏ผŒ้€‚ๅˆๅฏน็จณๅฎšๆ€ง่ฆๆฑ‚้ซ˜ใ€ๆœ‰ umi ๆŠ€ๆœฏๆ ˆ็š„ๅ›ข้˜Ÿ
  • Wujie๏ผš้š”็ฆปๅฝปๅบ•๏ผŒๆ”น้€ ๆˆๆœฌไฝŽ๏ผŒๅˆ›ๆ–ฐ็š„ๅŒๅฎนๅ™จๆžถๆž„๏ผŒ้€‚ๅˆๅฏน้š”็ฆป่ฆๆฑ‚้ซ˜ใ€้œ€่ฆไฟๆดปๆจกๅผใ€ๅญๅบ”็”จๆ”น้€ ๅ—้™็š„ๅœบๆ™ฏ

ไธคไธชๆก†ๆžถๅ„ๆœ‰ๅƒ็ง‹๏ผŒ้€‰ๅž‹ๆ—ถ้œ€่ฆๆ นๆฎ้กน็›ฎๅฎž้™…ๆƒ…ๅ†ต๏ผŒๆƒ่กก้š”็ฆป่ƒฝๅŠ›ใ€ๆ”น้€ ๆˆๆœฌใ€ๅ›ข้˜Ÿ็†Ÿๆ‚‰ๅบฆใ€็”Ÿๆ€ๆ”ฏๆŒ็ญ‰ๅ› ็ด ็ปผๅˆ่€ƒ่™‘ใ€‚


๐Ÿ“ฆ ๆบ็ ๅ‚่€ƒ๏ผš

๐Ÿ“š ็›ธๅ…ณไธ“ๆ ๏ผš