Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
文最初發(fā)布于 Bits and Pieces 博客,經(jīng)原作者授權(quán)由 InfoQ 中文站翻譯并分享。
微前端是一個(gè)可以追溯到多年前的新趨勢。隨著新方法的出現(xiàn)以及各種挑戰(zhàn)被克服,它們正在慢慢地進(jìn)入主流。但遺憾的是,許多非常明顯的認(rèn)識(shí)誤區(qū),讓許多人很難理解微前端到底是什么。
簡而言之,微前端就是將微服務(wù)的一些好處引入前端。除此之外,我們不應(yīng)該忘記,微服務(wù)也不是什么“銀彈”。
提示:要在微前端或任何其他項(xiàng)目之間共享 React/Angular/Vue 組件,可以使用像 Bit 這樣的工具。它允許你從任何代碼庫中“harvest”組件,并將它們共享到 bit.dev 的一個(gè)集合中。它讓團(tuán)隊(duì)可以在任何存儲(chǔ)庫中使用你的組件。使用它可以優(yōu)化協(xié)作、加速開發(fā)和保持 UI 一致性。
示例:在 bit.dev 中查找共享 React 組件
我想列一下在過去幾個(gè)月中,我最常聽到的關(guān)于微前端的誤解。先從從一個(gè)明顯的例子開始。
目前,許多微前端解決方案都是 JavaScript 框架。這怎么可能錯(cuò)呢?JavaScript 不再是可選的。每個(gè)人都想要高度交互的體驗(yàn),而 JS 在提供這些體驗(yàn)中發(fā)揮著至關(guān)重要的作用。
除了加載速度快、可訪問 Web 應(yīng)用的優(yōu)點(diǎn)外,還有其他因素應(yīng)該考慮。因此,許多 JavaScript 框架都提供了 isomorphic 渲染能力。最終,這讓它們不僅能夠在客戶端進(jìn)行拼接(stitch),還能在服務(wù)器上準(zhǔn)備好一切。如果有性能要求(如第一次有意義渲染的初始時(shí)間),這個(gè)選項(xiàng)聽起來很不錯(cuò)。
請記住,isomorphic 渲染有其自身的挑戰(zhàn)。
然而,即使一個(gè) JavaScript 解決方案沒有提供 isomorphic 呈現(xiàn),這也沒什么問題。如果不想在構(gòu)建微前端時(shí)使用 JavaScript,我們當(dāng)然可以這樣做。有許多模式,其中很多根本不需要 JavaScript。
考慮一種“比較舊的”模式:使用<frameset>。我聽見你笑了?好吧,有一些現(xiàn)如今人們試圖做的分割,它以前就支持了(下文有更詳細(xì)的討論)。一個(gè)頁面(可能由另一個(gè)服務(wù)渲染)負(fù)責(zé)菜單,而另一個(gè)頁面負(fù)責(zé)標(biāo)題。
復(fù)制代碼
<frameset cols="25%,*,25%"> <frame src="menu.html"> <frame src="content.html"> <frame src="sidebar.html"></frameset>
如今,我們使用更靈活(且仍然受到活躍支持)的<iframe>元素。它們提供了一些很好的特性——最重要的是使得不同的微前端相互隔離,但仍然可以通過postMessage進(jìn)行通信。
在 JavaScript 認(rèn)識(shí)誤區(qū)之后,這是下一個(gè)層次。當(dāng)然,在客戶端有多種技術(shù)可以實(shí)現(xiàn)微前端,實(shí)際上,我們甚至不需要<iframe>或任何類似的技術(shù)。
微前端可以像服務(wù)器端“includes”一樣簡單。有了諸如 Edge Side Includes 之類的高級技術(shù),這將變得更加強(qiáng)大。如果我們排除了在微前端功能中實(shí)現(xiàn)的微前端場景,那么即使是簡單的鏈接也可以很好的工作。最終,微前端解決方案也能像小而獨(dú)立的服務(wù)器端渲染器一樣簡單。每個(gè)渲染器可能只有一個(gè)頁面那么小。
下圖展示了在反向代理中發(fā)生的更高級的拼接:
通過反向代理實(shí)現(xiàn)服務(wù)器端拼接
當(dāng)然,可能 JavaScript 有許多優(yōu)點(diǎn),但它仍然高度依賴于你試圖通過微前端解決的問題。根據(jù)你的需要,服務(wù)器端解決方案可能仍然是最好的(或者至少是更好的)選擇。
在幾乎每一個(gè)關(guān)于微前端的教程中,不同的部分不僅由不同的團(tuán)隊(duì)開發(fā),而且使用了不同的技術(shù)。這是假的。
適當(dāng)?shù)奈⑶岸朔椒赡苁褂貌煌募夹g(shù),但是,這不應(yīng)該是目標(biāo)。我們做微服務(wù)也不只是為了在后端拼湊技術(shù)。如果我們使用多種技術(shù),那只是因?yàn)槲覀儷@得了一個(gè)特定的好處。
我們的目標(biāo)應(yīng)該始終是某種統(tǒng)一性。最好的方法是考慮一個(gè)新項(xiàng)目:我們會(huì)怎么做?如果答案是“使用單一框架”,那么我們就走上正軌了。
長遠(yuǎn)來看,有很多原因可以解釋為什么應(yīng)用程序中會(huì)出現(xiàn)多個(gè)框架。可能是遺留的,可能為了方便,也可能是一個(gè)概念驗(yàn)證。無論是什么原因:能夠處理這種場景還是不錯(cuò)的,但它絕不應(yīng)該是開始就希望達(dá)到的狀態(tài)。
不管你的微前端框架多高效——使用多個(gè)框架總是要付出不可忽視的代價(jià)。不僅初始渲染會(huì)花費(fèi)更長的時(shí)間,而且內(nèi)存消耗也會(huì)朝著錯(cuò)誤的方向發(fā)展。不能使用方便模型(例如,針對某個(gè)框架的模式庫)。需要更多的重復(fù)。最終,程序的 Bug 數(shù)量、不一致行為和可感知的響應(yīng)性都會(huì)受到影響。
一般來說,這沒有多大意義。我還沒見過微服務(wù)后端的數(shù)據(jù)處理在一個(gè)服務(wù)中而 API 在另一個(gè)服務(wù)中。通常,服務(wù)由多個(gè)層組成。雖然某些技術(shù)內(nèi)容(如日志記錄)肯定會(huì)引入到公共服務(wù)中,但有時(shí)也會(huì)使用諸如 Sidecar 之類的技術(shù)。此外,還需要通用服務(wù)編程技術(shù)。
對于微前端,情況也是如此。為什么一個(gè)微前端只能做菜單?每個(gè)微前端都有相應(yīng)的菜單嗎?拆分應(yīng)該根據(jù)業(yè)務(wù)需求來做,而不是技術(shù)決策。如果你讀過一些關(guān)于領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的書,你就會(huì)知道它是關(guān)于定義這些領(lǐng)域的——而這個(gè)定義與任何技術(shù)要求無關(guān)。
考慮以下劃分:
按布局分解成微前端
這些都是技術(shù)組件,和微前端無關(guān)。在一個(gè)真實(shí)的微前端應(yīng)用程序中,屏幕可能看起來是這樣的。
按領(lǐng)域分解成微前端
的確,這里的拼接要復(fù)雜得多,但這是一個(gè)可靠的微前端應(yīng)用程序應(yīng)該為你提供的!
不。你應(yīng)該共享那些值得共享的東西。你絕對不應(yīng)該共享所有東西(見下一條)。但要做到始終如一,你至少需要共享一套原則。至于是通過共享庫、共享 URL,或者只是在構(gòu)建或設(shè)計(jì)應(yīng)用程序時(shí)使用的文檔,那就不重要了。
對于微服務(wù),“無共享”架構(gòu)如下圖所示:
微服務(wù)的“無共享”架構(gòu)
在瀏覽器中,這將導(dǎo)致使用<iframe>,因?yàn)槟壳皼]有其他方法可以防止資源泄漏。使用影子 DOM,則 CSS 可能會(huì)被隔離,但腳本層面仍然能訪問所有內(nèi)容。
即使想遵循無共享的架構(gòu),我們也會(huì)遇到麻煩。
當(dāng)然,共享的程度越深(例如,使用一個(gè)通過應(yīng)用 shell 追加到 DOM 的共享庫),就越會(huì)出問題。另一方面,共享程度越淺(例如,只是一個(gè)指定基本設(shè)計(jì)元素的文檔),就會(huì)出現(xiàn)更多的不一致性。
絕對不是。如果這樣想,那么單體更有意義。就性能而言,這可能已經(jīng)是一個(gè)問題了。什么可以延遲加載?我們能去掉一些東西嗎?但真正的問題是依賴管理。什么都不能更新,因?yàn)樗赡軙?huì)破壞某個(gè)東西。
共享部件的好處是一致性保證。
現(xiàn)在,如果我們共享所有的東西,我們就是用復(fù)雜性來換一致性。這種一致性是不可維護(hù)的,因?yàn)閺?fù)雜性會(huì)在每個(gè)角落引入 Bug。
問題的根源在于“依賴地獄”。下圖很好地說明了這一點(diǎn)。
簡而言之,如果一切都相互依賴,那么我們就會(huì)有依賴問題。僅僅更新一個(gè)方框就會(huì)影響整個(gè)系統(tǒng)。一致嗎?確實(shí)。簡單的?絕不。
為什么只是 Web?誠然,到目前為止,我們接觸到的主要是 Web,但其概念和想法可以應(yīng)用于任何類型的應(yīng)用程序(移動(dòng)應(yīng)用、客戶端應(yīng)用……甚至是 CLI 工具)。在我看來,微前端只是“插件架構(gòu)”的一個(gè)花哨叫法。不過,插件接口如何設(shè)計(jì),以及運(yùn)行使用插件的應(yīng)用程序需要具備什么條件,這就是另外一回事了。
下圖顯示了一個(gè)非常通用的插件架構(gòu),來自 Omar Elgabry :
通用插件架構(gòu)
該架構(gòu)并沒有在哪里運(yùn)行的概念。它既可以在手機(jī)上運(yùn)行,也能在 Windows 上運(yùn)行,甚至還能在服務(wù)器上運(yùn)行。
為什么?如果解決方案超級復(fù)雜,那么我肯定會(huì)找一個(gè)簡單的。有些問題需要復(fù)雜的解決方案,但好的解決方案通常是簡單的。
根據(jù)場景的不同,它甚至可能不需要一個(gè)分布式團(tuán)隊(duì)。擁有分布式團(tuán)隊(duì)是采用微前端的首要原因之一,但這不是唯一原因。另一個(gè)很好的理由是特性的粒度。
如果從業(yè)務(wù)的角度來看微前端,那么你就會(huì)發(fā)現(xiàn),擁有啟用和關(guān)閉特定特性的能力是很有意義的。針對不同的市場,使用不同的微前端。回到一個(gè)簡單的權(quán)限模式,這是有意義的。不需要編寫代碼來根據(jù)特定條件打開或關(guān)閉某些東西。所有這些都留給公共層,可以根據(jù)(可能是動(dòng)態(tài)的)條件激活或停用。
這樣,不能(或不應(yīng)該)使用的代碼也不會(huì)被交付。雖然這不應(yīng)該是一個(gè)保護(hù)層,但它肯定是一個(gè)便捷(和性能)層。用戶不會(huì)感到困惑,因?yàn)樗麄兛吹降氖撬麄兡茏龅摹K麄兛床坏經(jīng)]有交付的功能,所以沒有字節(jié)浪費(fèi)在不可用的代碼上。
對于任何類型的實(shí)現(xiàn)(或供討論的底層架構(gòu)),開發(fā)經(jīng)驗(yàn)都可能遭到削弱。應(yīng)對這種情況的唯一方法是開發(fā)人員優(yōu)先。實(shí)現(xiàn)中的第一原則應(yīng)該是:使調(diào)試和開發(fā)成為可能。采用標(biāo)準(zhǔn)的工具。
有些微前端框架根本不接受這一點(diǎn)。有些需要在線連接、專用環(huán)境、多重服務(wù)……這不應(yīng)該是標(biāo)準(zhǔn),也絕不是常態(tài)。
解耦的模塊化后端可能為解耦前端打下了一個(gè)很好的基礎(chǔ),但通常情況下,情況并非如此。后端單體,前端模塊化,也是完全可行的,例如,為簡化個(gè)性化可能就要結(jié)合授權(quán)、權(quán)限和市場。
實(shí)際上,同樣,微服務(wù)后端并不能證明適合將類似的模式應(yīng)用于前端。許多微服務(wù)后端都是由單用途的應(yīng)用程序操作的,它們的功能沒有增加,只是外觀發(fā)生了改變。
我已經(jīng)讀到過好幾次,要?jiǎng)?chuàng)建一個(gè)微前端解決方案,就需要利用單存儲(chǔ)庫,最好使用像 Lerna 這樣的工具。我不認(rèn)可這一點(diǎn)。當(dāng)然,單存儲(chǔ)庫有一些優(yōu)點(diǎn),但也有明顯的缺點(diǎn)。
雖然有一些微前端框架需要聯(lián)合 CI/CD 構(gòu)建,但大多數(shù)都不需要。聯(lián)合 CI/CD 構(gòu)建通常會(huì)導(dǎo)致單存儲(chǔ)庫,因?yàn)槠湓O(shè)置要簡單得多。但對我來說,這是單體重新打包。如果你在單存儲(chǔ)庫上進(jìn)行聯(lián)合構(gòu)建,那么你就失去了讓微前端富有吸引力的兩個(gè)非常重要的優(yōu)點(diǎn):
不管怎樣,如果你看到微前端解決方案需要單存儲(chǔ)庫:那樣做就行。一個(gè)精心設(shè)計(jì)的單體系統(tǒng)可能會(huì)更好,它不會(huì)有分布式系統(tǒng)的所有問題。
微前端技術(shù)并不適合所有人。我不認(rèn)為微前端是未來的發(fā)展趨勢,但我也相信它們在未來會(huì)發(fā)揮重要作用。
關(guān)注我并轉(zhuǎn)發(fā)此篇文章,私信我“領(lǐng)取資料”,即可免費(fèi)獲得InfoQ價(jià)值4999元迷你書,點(diǎn)擊文末「了解更多」,即可移步InfoQ官網(wǎng),獲取最新資訊~
Frameset 對象
Frameset 對象代表 HTML 框架集。
HTML frameset 元素?fù)碛袃蓚€(gè)或者更多的 frame 元素。每個(gè)frame 元素?fù)碛幸粋€(gè)單獨(dú)的文件。/p>
HTML frameset 元素規(guī)定框架集只有幾行或列會(huì)。
Frameset 對象屬性
W3C: W3C 標(biāo)準(zhǔn)。
屬性 | 描述 | W3C |
---|---|---|
cols | 設(shè)置或返回框架集中列的數(shù)目。 | Yes |
rows | 設(shè)置或返回框架集中行的數(shù)目。 | Yes |
Frameset 對象事件
事件 | 描述 | W3C |
---|---|---|
onload | 在頁面載入完成后立即執(zhí)行腳本。 | Yes |
標(biāo)準(zhǔn)屬性和事件
Frameset 對象同樣支持標(biāo)準(zhǔn)的 屬性 和 事件。
如您還有不明白的可以在下面與我留言或是與我探討QQ群308855039,我們一起飛!
rame 的最主要功能是用來把一個(gè)頁面劃分成好幾個(gè)小窗口頁面,每個(gè)小窗口可以顯示不同html文件,這樣頁面也可以稱為框架結(jié)構(gòu)頁面,每個(gè)月小窗口稱作框架窗口,下來將詳細(xì)介紹框架窗口。
frame 在現(xiàn)在已經(jīng)很少使用,雖然不是必須學(xué)習(xí)的,但還是建議了解學(xué)習(xí)下frame 、iframe的知識(shí),在某些時(shí)候非常有用。
如果想將頁面分成上下兩部分,各自互相獨(dú)立又互相關(guān)聯(lián),用戶在其中一個(gè)部分操作頁面不影響其它部分的頁面,這樣的頁面也叫多窗口頁面。
1、框架窗口基本結(jié)構(gòu):
框架窗口主要包含2部分,一個(gè)是框架集,一個(gè)是具體的框架文件。
框架集就是存放框架結(jié)構(gòu)的文件,也是訪問框架文件的入口,如果網(wǎng)頁由上下2個(gè)框架窗口組成,那么除了這2個(gè)窗口的html文件,還有一個(gè)總的框架集文件。
框架文件是每個(gè)顯示區(qū)域?qū)?yīng)的html文件,如下示例:
index.html
<html>
<head>
<title>框架頁面</title>
</head>
<body>
<frameset>
<frame src="top.html"></frame>
<frame src="bottom.html"></frame>
</frameset>
</body>
</html>
如上index.html 就是框架集文件,在這個(gè)框架集文件中定義了頁面劃分成上下2部分,分別對應(yīng)top.html 和 bottom.html 2個(gè)框架窗口文件。
2、框架窗口分割
框架頁面分割方式是在框架集frameset通過rows 或 cols 屬性定義的,一般按分割類型分為以下幾種:
2.1 水平分割窗口
將頁面按水平方向分割,也就是上下結(jié)構(gòu),語法:
<frameset rows="窗口1高度,窗口2高度,">
<frame src="top.html"></frame>
<frame src="bottom.html"></frame>
</frameset>
在該語法中,rows 可以設(shè)置多個(gè)值,每個(gè)值對應(yīng)一個(gè)框架窗口垂直高度,它的值可以使用像素單位或百分比單位。
如下示例:
<html>
<frameset rows="25%,50%,25%">
<frame src="/example/html/frame_a.html">
<frame src="/example/html/frame_b.html">
<frame src="/example/html/frame_c.html">
</frameset>
</html>
顯示效果:
比如上面這個(gè),被從上到下分割成3個(gè)窗口,高度依次是25%,50%,25%。
2.2 垂直分割窗口
沿著頁面垂直方向分割,也就是左右結(jié)構(gòu)的多窗口頁面。語法如下:
<frameset cols="窗口1寬度,窗口2寬度,">
<frame src="left.html"></frame>
<frame src="right.html"></frame>
</frameset>
在該語法中,cols 可以設(shè)置多個(gè)值,每個(gè)值對應(yīng)一個(gè)框架窗口水平寬度,它的值可以使用像素單位或百分比單位。
示例:
<html>
<frameset cols="25%,50%,25%">
<frame src="/example/html/frame_a.html">
<frame src="/example/html/frame_b.html">
<frame src="/example/html/frame_c.html">
</frameset>
</html>
顯示效果:
比如上面這個(gè),被從左到右分割成3個(gè)窗口,寬度依次是25%,50%,25%。
2.3、嵌套分割窗口
嵌套窗口就是在一個(gè)頁面既有水平分割又有垂直分割的窗口,如下示例:
先水平分割再垂直分割
<frameset rows="50%,50%">
<frame src="/example/html/frame_a.html">
<frameset cols="25%,75%">
<frame src="/example/html/frame_b.html">
<frame src="/example/html/frame_c.html">
</frameset>
</frameset>
顯示效果:
先垂直分割再水平分割
<frameset cols="50%,50%">
<frame src="/example/html/frame_a.html">
<frameset rows="25%,75%">
<frame src="/example/html/frame_b.html">
<frame src="/example/html/frame_c.html">
</frameset>
</frameset>
顯示效果:
理論上可以無限嵌套,是不是很好玩。
2.4、noframes
當(dāng)瀏覽器布置frame 時(shí)會(huì)顯示noframes 中的內(nèi)容。如下代碼:
<html>
<frameset rows="50%,50%" frameborder="1" framespacing="100" bordercolor="blue">
<frame src="/example/html/frame_a.html">
<frameset cols="25%,75%" frameborder="0" bordercolor="orange">
<frame src="/example/html/frame_b.html">
<frame src="/example/html/frame_c.html">
</frameset>
</frameset>
</html>
效果顯示:
1、設(shè)置邊框 —— frameborder
frameborder 等于0時(shí)不顯示邊框,默認(rèn)顯示。
2、邊框?qū)挾?—— framespacing
在html5中無效。
3、邊框顏色 —— bordercolor
如下代碼:
<html>
<frameset rows="50%,50%" frameborder="1" framespacing="100" bordercolor="blue">
<frame src="/example/html/frame_a.html">
<frameset cols="25%,75%" frameborder="0" bordercolor="orange">
<frame src="/example/html/frame_b.html">
<frame src="/example/html/frame_c.html">
</frameset>
</frameset>
</html>
效果:
具體可以參考這里 https://www.cnblogs.com/lavenderzh/archive/2012/04/09/2438803.html 查看這幾個(gè)屬性的關(guān)系。
1、頁面源文件 —— src
就是每個(gè)框架窗口對應(yīng)的html文件,這里可以是圖片或其它文件。
<frame src="文件地址">
2、頁面名稱 —— name
給每個(gè)框架窗口設(shè)置名稱,有助于鏈接或查找窗口。
<frame src="文件地址" name="頁面名稱">
3、禁止調(diào)整窗口尺寸 —— noresize
黨員鼠標(biāo)拖到框架邊框時(shí),會(huì)發(fā)現(xiàn)鼠標(biāo)形狀變成可拖動(dòng)的,可以改不框架窗口寬度或高度。如果不希望改變窗口寬度或高度,可以使用noresize 屬性。
如下示例:
<html>
<frameset cols="25%,50%,25%">
<frame noresize="noresize" src="/example/html/frame_a.html">
<frame src="/example/html/frame_b.html">
<frame src="/example/html/frame_c.html">
</frameset>
</html>
窗口a是不可改變寬度的。
浮動(dòng)框架是一種特殊的框架,它是在主窗口中嵌套一個(gè)子窗口,也就是整個(gè)頁面不是框架頁面,但卻包含了一個(gè)框架窗口。
示例:
<iframe name="名稱" src="https://www.w3school.com.cn/" width="800px" height="600px"></iframe>
效果如下:
1、浮動(dòng)框架邊框 —— frameborder
frameborder 屬性規(guī)定是否顯示 iframe 周圍的邊框。設(shè)置屬性值為 "0" 就可以移除邊框:
<iframe src="demo_iframe.htm" frameborder="0"></iframe>
顯示效果:
2、鏈接到框架頁面
通過 a 標(biāo)簽的 target 屬性可以跳轉(zhuǎn)到框架頁面,示例如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鳥教程(runoob.com)</title>
</head>
<body>
<iframe src="http://www.runoob.com/" name="iframe_a"></iframe>
<p><a href="https://mp.toutiao.com/" target="iframe_a">頭條號(hào)</a></p>
<p><a href="http://www.runoob.com/" target="iframe_a">菜鳥教程</a></p>
</body>
</html>
顯示效果如下,點(diǎn)擊下面2個(gè)鏈接,切換窗口。
frame 和 iframe 浮動(dòng)框架用途很廣,比如可以實(shí)現(xiàn)頁面局部刷新,在之前被廣泛使用,但是現(xiàn)在基本不建議使用,它有很多問題,比如安全性,性能方面等。
當(dāng)然有時(shí)也會(huì)使用iframe,比如打印pdf,下載文件等等。
上篇:前端入門——html 表單控件使用
*請認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。