<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Micro Frontends &#8211; 科技島-掌握科技新聞、科技職場最新資訊</title>
	<atom:link href="https://www.technice.com.tw/tag/micro-frontends/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.technice.com.tw</link>
	<description>專注於科技新聞、科技職場、科技知識相關資訊，包含生成式AI、人工智慧、Web 3.0、區塊鏈、科技職缺百科、生物科技、軟體發展、雲端技術等豐富內容，適合熱衷科技及從事科技專業人事第一手資訊的平台。</description>
	<lastBuildDate>Wed, 30 Nov 2022 09:38:02 +0000</lastBuildDate>
	<language>zh-TW</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.4.2</generator>

<image>
	<url>https://www.technice.com.tw/wp-content/uploads/2022/12/cropped-wordpress_512x512-150x150.png</url>
	<title>Micro Frontends &#8211; 科技島-掌握科技新聞、科技職場最新資訊</title>
	<link>https://www.technice.com.tw</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>後端有 Microservices，那前端呢？初探 Micro Frontends 的世界</title>
		<link>https://www.technice.com.tw/experience/28597/</link>
					<comments>https://www.technice.com.tw/experience/28597/#respond</comments>
		
		<dc:creator><![CDATA[科編推薦]]></dc:creator>
		<pubDate>Wed, 30 Nov 2022 09:38:01 +0000</pubDate>
				<category><![CDATA[產業]]></category>
		<category><![CDATA[Micro Frontends]]></category>
		<category><![CDATA[前端]]></category>
		<category><![CDATA[工作甘苦談]]></category>
		<category><![CDATA[工程師]]></category>
		<category><![CDATA[科技業]]></category>
		<guid isPermaLink="false">https://www.technice.com.tw/?p=28597</guid>

					<description><![CDATA[<p><img width="1200" height="627" src="https://www.technice.com.tw/wp-content/uploads/2022/11/image-23-1.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="image 23 1" decoding="async" srcset="https://www.technice.com.tw/wp-content/uploads/2022/11/image-23-1.png 1200w, https://www.technice.com.tw/wp-content/uploads/2022/11/image-23-1-300x157.png 300w, https://www.technice.com.tw/wp-content/uploads/2022/11/image-23-1-1024x535.png 1024w, https://www.technice.com.tw/wp-content/uploads/2022/11/image-23-1-768x401.png 768w" sizes="(max-width: 1200px) 100vw, 1200px" title="後端有 Microservices，那前端呢？初探 Micro Frontends 的世界 1"></p>
<p>最近筆者在工作上一直聽到後端工程師們在談論 Microservices 的架構設計，聽到的當下立馬去查詢才知道原來 Microservices 這麼潮，身為前端工程師的我當然也希望前端也可以有這麼新穎的架構，於是這篇文章就要來跟讀者介紹 Micro Frontends。<content><!-- wp:image {"align":"center","id":28598,"sizeSlug":"full","linkDestination":"none"} --></p>
<figure class="wp-block-image aligncenter size-full"><img src="https://www.technice.com.tw/wp-content/uploads/2022/11/image-8-4.png" alt="" class="wp-image-28598"/><figcaption>Photo by <a href="https://unsplash.com/@cookiethepom" target="_blank" rel="noreferrer noopener">Cookie the Pom</a> on <a href="https://unsplash.com/" target="_blank" rel="noreferrer noopener">Unsplash.com</a></figcaption></figure>
<p><!-- /wp:image --></p>
<p><!-- wp:paragraph --></p>
<p>文／<a href="https://medium.com/starbugs/%E5%BE%8C%E7%AB%AF%E6%9C%89-microservices-%E9%82%A3%E5%89%8D%E7%AB%AF%E5%91%A2-%E5%88%9D%E6%8E%A2-micro-frontends-%E7%9A%84%E4%B8%96%E7%95%8C-e3c5a4f21798">Andy Chen</a></p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:heading --></p>
<h2 id="9958">前言</h2>
<p><!-- /wp:heading --></p>
<p><!-- wp:paragraph --></p>
<p id="5adf">最近筆者在工作上一直聽到後端工程師們在談論&nbsp;<a href="https://zh.wikipedia.org/zh-tw/%E5%BE%AE%E6%9C%8D%E5%8B%99" rel="noreferrer noopener" target="_blank"><strong>Microservices</strong></a>&nbsp;的架構設計，聽到的當下立馬去查詢才知道原來&nbsp;<strong>Microservices</strong>&nbsp;這麼潮，身為前端工程師的我當然也希望前端也可以有這麼新穎的架構，於是這篇文章就要來跟讀者介紹&nbsp;<strong>Micro Frontends</strong>。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:heading --></p>
<h2 id="01e0">什麼是 Microservices？</h2>
<p><!-- /wp:heading --></p>
<p><!-- wp:paragraph --></p>
<p id="7871">在開始進入本篇文章主題之前要先跟讀者們介紹什麼是&nbsp;<strong>Microservices</strong>。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p id="e93d"><strong>Microservices&nbsp;</strong>是一種軟體架構，專注開發在每一個小型功能或者服務上，最後再利用模組化的方式組合出一個大型的應用程式。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p id="e423">如果讀者是前端工程師的話可能會覺得上面的敘述很像是 ES6 module 的架構，開發者只需要專注在每個 module 上的開發，最後再利用 Bundler 打包這些 module 形成一個完整的頁面甚至是應用程式，像下圖這樣。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:image {"align":"center","id":28599,"sizeSlug":"full","linkDestination":"none"} --></p>
<figure class="wp-block-image aligncenter size-full"><img src="https://www.technice.com.tw/wp-content/uploads/2022/11/image-9-4.png" alt="" class="wp-image-28599"/><figcaption>Webpack module bundler</figcaption></figure>
<p><!-- /wp:image --></p>
<p><!-- wp:paragraph --></p>
<p id="1a69">不過後端跟前端完全不一樣，後端是藉由一個又一個的 request 來 real time 的執行相關的程式碼，所以在 <strong>Microservices</strong> 的架構中，想要讓一個又一個的服務能互相溝通，這時候就是要仰賴各個 API 了。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:image {"align":"center","id":28600,"sizeSlug":"full","linkDestination":"none"} --></p>
<figure class="wp-block-image aligncenter size-full"><img src="https://www.technice.com.tw/wp-content/uploads/2022/11/image-10-4.png" alt="" class="wp-image-28600"/><figcaption>Simple Microservices Structure</figcaption></figure>
<p><!-- /wp:image --></p>
<p><!-- wp:paragraph --></p>
<p id="b0fc">但這時候會有一個很大的問題，假如這三個 Service 對於前端來講有高度相依性，以上圖為例：今天一個完整的購物網站必須要先讓使用者登入後才可以進行購買商品以及去購物車結帳，這時候在 Client 端就必須要分別打三次 API 並且互相等待才可以完成這整個流程，甚至假如剛好不小心有一個 Service 壞了需要重新啟動，這時候可能會先產生一個過渡期的 API 避免 Client 端打到有問題的 Service，可是 Client 端也不可能每次都會去記住這個新產生的 API，所以這勢必會造成一個很大問題。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p id="ba1e">這時候其實可以在這些 Services 上添加一個 <strong>API Gateway</strong>，對於 Client 端來說我只需要對到一個 Gateway 就好，對於這個 Gateway 來說我一樣是去呼叫各個 Service 並且把資料都處理完後再回傳給前端。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:image {"align":"center","id":28601,"sizeSlug":"full","linkDestination":"none"} --></p>
<figure class="wp-block-image aligncenter size-full"><img src="https://www.technice.com.tw/wp-content/uploads/2022/11/image-11-5.png" alt="" class="wp-image-28601"/><figcaption>Microservices with API Gateway Structure</figcaption></figure>
<p><!-- /wp:image --></p>
<p><!-- wp:paragraph --></p>
<p id="7107">如果有讀者本身是 SRE 熟悉 Docker 或者 K8s 這種用來自動部屬容器化應用程式的平台，對於上面這張圖應該更熟悉了！像 K8s 就有類似&nbsp;<strong>API Gateway</strong>&nbsp;的&nbsp;<a href="https://kubernetes.io/docs/concepts/services-networking/ingress/" rel="noreferrer noopener" target="_blank">Ingress&nbsp;</a>而 Docker 則有&nbsp;<a href="https://docs.docker.com/engine/swarm/ingress/" rel="noreferrer noopener" target="_blank">routing mesh</a>。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p id="7e5f">不過光有 <strong>API Gateway</strong> 其實還沒辦法凸顯 <strong>Microservices </strong>的特色，在 <strong>Microservices </strong>的架構中其實每個 Service 都可以有自己的 DB，目的就是為了不要讓每個 Service 之間會互相關聯。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:image {"align":"center","id":28602,"sizeSlug":"full","linkDestination":"none"} --></p>
<figure class="wp-block-image aligncenter size-full"><img src="https://www.technice.com.tw/wp-content/uploads/2022/11/image-12-3.png" alt="" class="wp-image-28602"/><figcaption>Final Microservice structure</figcaption></figure>
<p><!-- /wp:image --></p>
<p><!-- wp:paragraph --></p>
<p id="0f02">但這樣做其實有幾個缺點：</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:list --></p>
<ul>
<li><strong>很難保證資料的一致性</strong></li>
</ul>
<p><!-- /wp:list --></p>
<p><!-- wp:paragraph --></p>
<p id="cf1f">以上圖為例，假如今天有一個 member 被註銷帳號，但這個 member 在被註銷帳號之前在 shopping cart 這個 Service 中有待結帳商品，這時候就會出現 member 資料不一致的問題。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:list --></p>
<ul>
<li><strong>DB 資料遺失</strong></li>
</ul>
<p><!-- /wp:list --></p>
<p><!-- wp:paragraph --></p>
<p id="9c3a">當某一個 Service 壞了需要重啟，這時候 DB 的資料有可能就會遺失導致後續的資料出現錯誤。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p id="2f21">為了改善這些缺點這時候就可以將這些 Service 的 DB 設計成可棄性，換句話說就是這些 DB 只是用來作為短期的資料存取而已，背後還有一個共用的大資料庫去更新這些資料，通常都會利用&nbsp;<a href="https://zh.wikipedia.org/zh-tw/Redis" rel="noreferrer noopener" target="_blank">Redis</a>&nbsp;這種 cache DB 來進行設計。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:heading --></p>
<h2 id="4095">為什麼需要 Microservices？</h2>
<p><!-- /wp:heading --></p>
<p><!-- wp:paragraph --></p>
<p id="ac29"><strong>Microservices&nbsp;</strong>的好處就是可以專注開發在每個小服務上，舉例來說以一個購票網站可能會在短時間內湧入大量的流量，這時候 race condition 就顯得相當重要，這時候就可以利用 Go 語言進行開發，亦或者是要開發一個以效能為主的服務，這時候就可以用 Rust 進行開發。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p id="70e2">上面也提到 <strong>Microservices </strong>必須要仰賴 API 之間的溝通，所以通常在企業等級的產品上都會有拆分模組販售的需求，假如這時候就是利用 <strong>Microservices </strong>架構進行開發的話就很好拆分每個服務了。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:image {"align":"center","id":28603,"sizeSlug":"full","linkDestination":"none"} --></p>
<figure class="wp-block-image aligncenter size-full"><img src="https://www.technice.com.tw/wp-content/uploads/2022/11/image-13-4.png" alt="" class="wp-image-28603"/><figcaption>使用 Microservices 架構的企業以及平台。來源：<a href="https://zh.wikipedia.org/zh-tw/%E5%BE%AE%E6%9C%8D%E5%8B%99" target="_blank" rel="noreferrer noopener">維基百科</a></figcaption></figure>
<p><!-- /wp:image --></p>
<p><!-- wp:paragraph --></p>
<p id="b446">這些都是使用&nbsp;<strong>Microservices&nbsp;</strong>後所能帶來的好處，所以假如讀者今天需要開發一個非常複查且龐大的平台，這時候不妨可以利用&nbsp;<strong>Microservices&nbsp;</strong>的架構進行開發喔！</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:heading --></p>
<h2 id="4726">Monolithic Architecture<strong>(</strong>單體式架構<strong>)</strong></h2>
<p><!-- /wp:heading --></p>
<p><!-- wp:paragraph --></p>
<p id="729d">講完了&nbsp;<strong>Microservices&nbsp;</strong>後相信讀者應該對於這種架構有了初步的認識，與&nbsp;<strong>Microservices&nbsp;</strong>不一樣的架構就是&nbsp;<strong>Monolithic Architecture(單體式架構)。</strong></p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p id="023d">一般來說我們正常開發都是使用 <strong>Monolithic Architecture</strong>，在 <strong>Monolithic Architecture </strong>的架構中都會把平台中所有內容都包裝起來，像下圖這樣：</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:image {"align":"center","id":28605,"sizeSlug":"full","linkDestination":"none"} --></p>
<figure class="wp-block-image aligncenter size-full"><img src="https://www.technice.com.tw/wp-content/uploads/2022/11/image-14-2.png" alt="" class="wp-image-28605"/><figcaption>Monolithic Architecture</figcaption></figure>
<p><!-- /wp:image --></p>
<p><!-- wp:paragraph --></p>
<p id="5827">這種架構不是不好，但假如今天想要拆分或者擴充平台上的 Service 其實都會比較麻煩一些，而且也會怕牽一髮而動全身，甚至所有的 Service 背後都會連到同一個 DB，這樣極有可能會讓 DB connection 同時連線過高導致 request 一直發送失敗，所以這也是&nbsp;<strong>Microservices&nbsp;</strong>想要解決的其中一個痛點。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:heading --></p>
<h2 id="ffe8">什麼是 Micro Frontends？</h2>
<p><!-- /wp:heading --></p>
<p><!-- wp:paragraph --></p>
<p id="02f1"><strong>Micro Frontends</strong>&nbsp;可以想像成前端版的&nbsp;<strong>Microservices</strong>，在後端的世界中強調一個又一個 Service 而在前端的世界中則是強調一個又一個的 modules，如何將網頁中每一個 module 有效的拆分就是&nbsp;<strong>Micro Frontends</strong>&nbsp;要做的工作。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:heading --></p>
<h2 id="48d5">Micro Frontends 的實現方式</h2>
<p><!-- /wp:heading --></p>
<p><!-- wp:paragraph --></p>
<p id="012a">接下來要跟讀者介紹的是&nbsp;<strong>Micro Frontends</strong>&nbsp;的實現方式，其實&nbsp;<strong>Micro Frontends</strong>&nbsp;有蠻多種實現方式的：</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:list --></p>
<ul>
<li><strong>iframe</strong></li>
</ul>
<p><!-- /wp:list --></p>
<p><!-- wp:paragraph --></p>
<p id="b684">透過 iframe 的特性讓每個被載入的區塊頁面都可以獨立運行，假如需要有資料上的溝通也可以利用&nbsp;<code>window.postMessage</code>&nbsp;來完成，但這樣做會有非常多的缺點，像是有可能載入同樣的程式碼、UI 難以控制、甚至可能會有潛在的資安風險，所以筆者還是建議讀者不要用此方式來進行&nbsp;<strong>Micro Frontends</strong>&nbsp;的實現方式。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:list --></p>
<ul>
<li><strong>Client side 利用 JavaScript 載入 module</strong></li>
</ul>
<p><!-- /wp:list --></p>
<p><!-- wp:paragraph --></p>
<p id="be75">這個方法簡單又粗暴，就是利用 JavaScript create 出 script tag 後，接著再用 script tag 去載入相關的 module，最後再將其內容塞進去對應的 div 內，但缺點就是無法使用 SSR，整體寫法會像下圖這樣。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:image {"align":"center","id":28606,"sizeSlug":"full","linkDestination":"none"} --></p>
<figure class="wp-block-image aligncenter size-full"><img src="https://www.technice.com.tw/wp-content/uploads/2022/11/image-15-3.png" alt="" class="wp-image-28606"/><figcaption>client side load modules by javascript</figcaption></figure>
<p><!-- /wp:image --></p>
<p><!-- wp:list --></p>
<ul>
<li><strong>Web Components</strong></li>
</ul>
<p><!-- /wp:list --></p>
<p><!-- wp:paragraph --></p>
<p id="adb6"><a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components" rel="noreferrer noopener" target="_blank"><strong>Web Components</strong></a>&nbsp;可以說是最多人拿來討論的&nbsp;<strong>Micro Frontends&nbsp;</strong>的實現方式了，雖然我們在現今的網頁架構中可以自由地 import 大神們寫好的套件，但難免都會遇到以下幾個問題：</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:list {"ordered":true} --></p>
<ol>
<li>套件相依性的問題：需要安裝只有該套件才會使用的 library，這會造成整個 node_modules 相當龐大。</li>
<li>Scope 問題：前端為了樣式上的變化通常都會有藉由許多的 className 來進行樣式上的改動，但有可能因為該套件也有撰寫一樣的 className 導致很多時候都需要各種 override，長期下來也會是一種專案維護上的負擔。</li>
<li>版本相容性問題：只要框架進行大改版，基本上就很容易出現套件無法兼容新版本的狀況，這時候只能等套件作者升級版本之後才能再次使用，相信這個狀況也是許多開發者都會面臨到的困境。</li>
</ol>
<p><!-- /wp:list --></p>
<p><!-- wp:nextpage --><br />
<!--nextpage--><br />
<!-- /wp:nextpage --></p>
<p><!-- wp:paragraph --></p>
<p id="4077">因此 <strong>Web Components</strong> 的出現就是希望可以解決上述的問題，而 <strong>Web Components</strong> 一共由以下三種元素組成：</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:list --></p>
<ul>
<li><strong>Custom elements</strong></li>
</ul>
<p><!-- /wp:list --></p>
<p><!-- wp:paragraph --></p>
<p id="eca5">自訂一個語意化標籤來引用 components，並且利用 JavaScript 來建立 custom elements、shadow DOM、HTML templates 三者之間的關聯，這種自定義標籤會像這樣：&nbsp;<code>&lt;my-custom-element&gt;&lt;/my-custom-element&gt;</code>&nbsp;。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:quote --></p>
<blockquote class="wp-block-quote">
<p>謎之音：這根本就是 Angular 的寫法阿XD</p>
</blockquote>
<p><!-- /wp:quote --></p>
<p><!-- wp:list --></p>
<ul>
<li><strong>Shadow DOM</strong></li>
</ul>
<p><!-- /wp:list --></p>
<p><!-- wp:paragraph --></p>
<p id="85ed">Shadow DOM 簡單來說就是在現有的 DOM tree 中產生出一個完全獨立於其他元素的 sub DOM tree，藉由此方法就可以讓 sub DOM tree 自己獨立運作並且不會干擾到其他 DOM tree 上的元素。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:list --></p>
<ul>
<li><strong>HTML templates</strong></li>
</ul>
<p><!-- /wp:list --></p>
<p><!-- wp:paragraph --></p>
<p id="39b6">利用&nbsp;<code><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template" rel="noreferrer noopener" target="_blank">&lt;template&gt;</a></code>&nbsp;以及&nbsp;<code><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot" rel="noreferrer noopener" target="_blank">&lt;slot&gt;</a></code>&nbsp;元素產生出具有複用性的 HTML 樣板。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p id="8707">感覺上&nbsp;<strong>Web Components</strong>&nbsp;的設計準則就可以當作是&nbsp;<strong>Micro Frontends</strong>&nbsp;的最好的實現方式，透過上述的三種方式就可以產生出一個獨立於原本專案而且又不會影響到頁面的 modules。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p id="5d86">可是這種開發方式其實不太符合每一種框架的設計理念(可能只有 Angular 體系最適合XD)，而且會讓一個 reusable component 開發起來蠻冗長的，所以&nbsp;<strong>Micro Frontends</strong>&nbsp;還是沒有被很多前端工程師所重視。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:list --></p>
<ul>
<li><strong>Webpack Module Federation</strong></li>
</ul>
<p><!-- /wp:list --></p>
<p><!-- wp:paragraph --></p>
<p id="cb97">假設我們今天有 A、B 兩個專案，其中 A 專案有元件發現是可以讓 B 專案進行複用的，這時候我們會有以下幾種作法達到這個需求：</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:list {"ordered":true} --></p>
<ol>
<li>將 A 專案中可以被複用的元件手動複製其程式碼至 B 專案。</li>
<li>將 A 專案中可以被複用的元件發佈到 npm 上，並且在 B 專案中安裝。</li>
<li>融合 A 專案與 B 專案並用&nbsp;<a href="https://medium.com/starbugs/%E6%B7%BA%E8%AB%87-monorepo-%E5%B8%B6%E4%BE%86%E7%9A%84%E6%95%88%E7%9B%8A-%E4%BB%A5-turborepo-%E7%82%BA%E4%BE%8B-615fb4af5ebd?source=user_profile---------2----------------------------">monorepo</a>&nbsp;的架構進行開發。</li>
</ol>
<p><!-- /wp:list --></p>
<p><!-- wp:paragraph --></p>
<p id="a2de">相信不管是哪個方法都相當複雜而且後續的維護成本也很高，而且隨著專案越來越大，之後的網站效能也是問題，即便用了 code splitting 或者是 dynamic import 能提昇的效能也有限。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p id="5355">不過這個聲音 Webpack 聽到了，在 Webpack 5 誕生後推出了一個全新的技術叫&nbsp;<a href="https://webpack.js.org/concepts/module-federation/" rel="noreferrer noopener" target="_blank"><strong>Module Federation</strong></a>，Module Federation 的誕生就是為了幫助開發者可以 import 外部專案已經 bundle 好的檔案，不用再經由額外的安裝步驟相當方便。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:heading --></p>
<h2 id="2fb2">Micro Frontends 實作 ft. Webpack Module Federation</h2>
<p><!-- /wp:heading --></p>
<p><!-- wp:paragraph --></p>
<p id="28ab">上面介紹完&nbsp;<strong>Micro Frontends</strong>&nbsp;的實現方式後，接下來就要進入本篇文章的實作篇了，這邊筆者會以&nbsp;<strong>Webpack Module Federation</strong>&nbsp;進行 Demo。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p id="1ac6">首先筆者先介紹&nbsp;<strong>Webpack Module Federation&nbsp;</strong>的相關設定，在&nbsp;<strong>Webpack Module Federation</strong>&nbsp;的世界中我們一共會分為 Remote 以及 Host 兩種設定區塊，分別代表的是 modules export 以及 import 的部分，首先先介紹 Remote 的部分，在這個 plugin 中我們一共可以設定幾個內容：</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:list --></p>
<ul>
<li><strong>name</strong></li>
</ul>
<p><!-- /wp:list --></p>
<p><!-- wp:paragraph --></p>
<p id="49ad">設定 export 出去的名字。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:list --></p>
<ul>
<li><strong>filename</strong></li>
</ul>
<p><!-- /wp:list --></p>
<p><!-- wp:paragraph --></p>
<p id="82a0">設定 export 出去的檔案名稱，最終的使用方式會在下方的 import 區塊做介紹，官方建議使用&nbsp;<code>remoteEntry.js</code>&nbsp;作為命名。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:list --></p>
<ul>
<li><strong>exposes</strong></li>
</ul>
<p><!-- /wp:list --></p>
<p><!-- wp:paragraph --></p>
<p id="621f">exposes 就是負責設定 modules 中需要被 export 的 components 檔案 path alias，通常這邊的寫法都會是&nbsp;<code>'./componentName': 'componentPath'</code>&nbsp;，在 key 的部分會用相對路徑的寫法原因是未來在 import 的時候就可以用上方設定好的 name 作為檔案抓去的進入點。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p id="bf03">舉例來說：我們有一個&nbsp;<code>Button.jsx</code>&nbsp;的檔案，這時候我們就可以在 exposes 的區塊寫上&nbsp;<code>'./Button': './src/Button'</code>&nbsp;，到時候在 import 的時候就可以寫上&nbsp;<code>'name/Button</code>&nbsp;的方式抓去這個檔案了。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:list --></p>
<ul>
<li><strong>shared</strong></li>
</ul>
<p><!-- /wp:list --></p>
<p><!-- wp:paragraph --></p>
<p id="703a">shared 則是當 components 有使用到相同的第三方套件時，可以用來設定的相關規範，基本上 shared 一共有三種呈現方式：</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:list {"ordered":true} --></p>
<ol>
<li><strong>Array syntax</strong>：只要在 Array 內寫上 package name 即可，寫法上會像這樣：&nbsp;<code>shared: ['lodash']</code></li>
<li><strong>Object syntax</strong>：可以更詳細的設定 package，會以 package name 作為 Object key，後方的 value 則可以設定此 package 的版本，寫法上會像這樣：&nbsp;<code>shared: { lodash: '^4.17.0' }</code></li>
<li><strong>Object with sharing hints</strong>：基於&nbsp;<strong>Object syntax&nbsp;</strong>的架構上，填入&nbsp;<strong>Webpack Module Federation&nbsp;</strong>可支援的相關 Sharing hints。</li>
</ol>
<p><!-- /wp:list --></p>
<p><!-- wp:paragraph --></p>
<p id="6730">在&nbsp;<strong>Object with sharing hints</strong>&nbsp;這邊一共可以設定非常多種內容，筆者這裡只單純說明幾個最常用的 sharing hints，想要了解所有的 sharing hints 的讀者可以參考這個<a href="https://webpack.js.org/plugins/module-federation-plugin#sharing-hints" rel="noreferrer noopener" target="_blank">連結</a>。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:list --></p>
<ul>
<li><strong>eager</strong>：讓 Webpack 可以直接存取 modules，如果設定為 false 則使用 async fetch 的方式去取得分離後的 chunk，若設定為 true 則會打包到 remoteEntry 方便進行直接抓取。</li>
<li><strong>requiredVersion</strong>：設定此 package 的版本。</li>
<li><strong>singleton</strong>：使用 singleton 就代表此 package 只允許一個版本，並且只加載一次，通常在&nbsp;<code>react</code>&nbsp;、&nbsp;<code>react-dom</code>&nbsp;這種有 global internal state 的 libarary 加上此設定更是重要。</li>
</ul>
<p><!-- /wp:list --></p>
<p><!-- wp:paragraph --></p>
<p id="4cb5">在 Shared 內筆者建議的寫法是基於目前專案的 package dependencies 上再額外疊加一些自己想要設定的 <strong>Object with sharing hints，</strong>最終設定完的長像會像下圖這樣：</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:image {"align":"center","id":28608,"sizeSlug":"full","linkDestination":"none"} --></p>
<figure class="wp-block-image aligncenter size-full"><img src="https://www.technice.com.tw/wp-content/uploads/2022/11/image-16-6.png" alt="" class="wp-image-28608"/><figcaption>Remote 相關 <strong>Webpack Module Federation </strong>設定</figcaption></figure>
<p><!-- /wp:image --></p>
<p><!-- wp:paragraph --></p>
<p id="ccbc">這裡筆者提醒一下讀者，假如讀者在設定的過程中有遇到這個錯誤：<strong>Uncaught Error: Shared module is not available for eager consumption</strong></p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p id="5192">代表讀者需要額外在新增一個檔案將 component render 到 DOM 的相關程式碼都複製上去，最後再到 <code>index.jsx</code> 中去 import 這個檔案。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:image {"align":"center","id":28609,"sizeSlug":"full","linkDestination":"none"} --></p>
<figure class="wp-block-image aligncenter size-full"><img src="https://www.technice.com.tw/wp-content/uploads/2022/11/image-17-3.png" alt="" class="wp-image-28609"/><figcaption>遇到 <strong>Shared module is not available for eager consumption </strong>解決方法</figcaption></figure>
<p><!-- /wp:image --></p>
<p><!-- wp:paragraph --></p>
<p>最終呈現在網頁上的畫面就會像下圖這樣：</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:image {"align":"center","id":28610,"sizeSlug":"full","linkDestination":"none"} --></p>
<figure class="wp-block-image aligncenter size-full"><img src="https://www.technice.com.tw/wp-content/uploads/2022/11/image-19-1.png" alt="" class="wp-image-28610"/></figure>
<p><!-- /wp:image --></p>
<p><!-- wp:paragraph --></p>
<p id="fdc8">再來是 Host 的部分，基本上設定的內容跟 Remote 大同小異，差別在於 Remote 需要設定 exposes 的 components 以及 filename ，而 Host 則是要設定該 Remote 的檔案位置。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p id="7eb0">在檔案位置中我們會以三種內容組合，寫法上會像這樣：&nbsp;<code>name@remoteURL/filename</code>&nbsp;，其中 name 就是上方介紹到的 export 出去的名稱，remoteURL 則是 Remote 區塊內 Webpack config 中所設定的 output path 相關設定，而 filename 則是上方介紹到的 export 出去的檔案名稱。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p id="5618">最終的寫法就會像下方這樣：</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:image {"align":"center","id":28611,"sizeSlug":"full","linkDestination":"none"} --></p>
<figure class="wp-block-image aligncenter size-full"><img src="https://www.technice.com.tw/wp-content/uploads/2022/11/image-20-1.png" alt="" class="wp-image-28611"/><figcaption>Host 相關 <strong>Webpack Module Federation </strong>設定</figcaption></figure>
<p><!-- /wp:image --></p>
<p><!-- wp:paragraph --></p>
<p>由於筆者在 shared 的區塊都沒有加上 <code>eager: true</code> ，所以這邊在抓取 components 時都是用 async 的方式去抓取，因此筆者建議會使用 <code>&lt;Suspense></code> 的方式進行 data fetching 這樣會比較安全喔！</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:image {"align":"center","id":28613,"sizeSlug":"full","linkDestination":"none"} --></p>
<figure class="wp-block-image aligncenter size-full"><img src="https://www.technice.com.tw/wp-content/uploads/2022/11/image-21-1.png" alt="" class="wp-image-28613"/><figcaption>Host 抓取 Remote 相關 Modules 時方法</figcaption></figure>
<p><!-- /wp:image --></p>
<p><!-- wp:paragraph --></p>
<p>最終呈現在網頁上的畫面就會像下圖這樣：</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:image {"align":"center","id":28616,"sizeSlug":"full","linkDestination":"none"} --></p>
<figure class="wp-block-image aligncenter size-full"><img src="https://www.technice.com.tw/wp-content/uploads/2022/11/image-22-2.png" alt="" class="wp-image-28616"/></figure>
<p><!-- /wp:image --></p>
<p><!-- wp:paragraph --></p>
<p>最後再附上這次的 demo repo 連結，有興趣的讀者歡迎下載來玩玩看喔！</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:list --></p>
<ul>
<li><a href="https://github.com/w5151381guy/micro-frontend-practice">https://github.com/w5151381guy/micro-frontend-practice</a></li>
</ul>
<p><!-- /wp:list --></p>
<p><!-- wp:heading --></p>
<h2 id="9e1f">小結</h2>
<p><!-- /wp:heading --></p>
<p><!-- wp:paragraph --></p>
<p id="300d">這次介紹了&nbsp;<strong>Micro Frontends</strong>&nbsp;以及&nbsp;<strong>Microservices&nbsp;</strong>這兩種目前最多人討論的架構，希望可以讓讀者更了解一些新時代的架構所帶來的優缺點，文章的篇幅可能有點多，讀者可以邊看邊消化一下這樣才能更好的理解所有的內容。</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p id="0338">最後也稍微介紹了一下&nbsp;<strong>Micro Frontends</strong>&nbsp;的實作，內容有點多可能比較難消化，如果讀者有任何文章上的問題都歡迎留言給我，至於&nbsp;<strong>Microservices&nbsp;</strong>的實作方式，由於筆者比較熟悉前端就無法介紹給讀者了?</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:paragraph --></p>
<p id="d1e8">最後如果讀者對於文章有任何問題都歡迎留言給我，之後筆者也會盡量多學一些不同的架構以及相關的知識再分享給大家，感謝各位讀者的收看~</p>
<p><!-- /wp:paragraph --></p>
<p><!-- wp:pullquote --></p>
<figure class="wp-block-pullquote">
<blockquote>
<p>本文由 <a href="https://medium.com/@w5151381guy">Andy Chen</a> 授權轉載，<a href="https://medium.com/starbugs/%E5%BE%8C%E7%AB%AF%E6%9C%89-microservices-%E9%82%A3%E5%89%8D%E7%AB%AF%E5%91%A2-%E5%88%9D%E6%8E%A2-micro-frontends-%E7%9A%84%E4%B8%96%E7%95%8C-e3c5a4f21798">原文連結</a></p>
</blockquote>
</figure>
<p><!-- /wp:pullquote --></content></p>
<p>這篇文章 <a rel="nofollow" href="https://www.technice.com.tw/experience/28597/">後端有 Microservices，那前端呢？初探 Micro Frontends 的世界</a> 最早出現於 <a rel="nofollow" href="https://www.technice.com.tw">科技島-掌握科技新聞、科技職場最新資訊</a>。</p>
]]></description>
		
					<wfw:commentRss>https://www.technice.com.tw/experience/28597/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
