微前端的一個(gè)簡單應(yīng)用
做為后端工程師,對微服務(wù)肯定耳熟能詳了,或者可以說,微服務(wù)已經(jīng)爛大街了。
基于微服務(wù)的事件驅(qū)動(dòng)系統(tǒng)的架構(gòu)考量
做為前端工程師,也有些類似的概念,那就是微前端。
很多年前,其實(shí)前端就已經(jīng)開始探索面向組件開發(fā)了,當(dāng)時(shí)有過一些 Web Component 的概念,我曾經(jīng)嘗試過,工程上很難用,兼容性又不好,后來似乎不溫不火漸漸沒有消息了。不過經(jīng)過多年的發(fā)展,前端框架層出不窮,如今面向組件開發(fā)已經(jīng)成為了很自然的事情了。
乾坤是一個(gè)優(yōu)秀的微前端框架,它的官網(wǎng)也說明了為什么會(huì)有微前端,為什么 iframe 不好用等等。但是如果不使用任何微前端框架,可以進(jìn)行微前端的開發(fā)嗎?答案是可以的,搞清楚本質(zhì)就行。當(dāng)然,如果項(xiàng)目比較大比較復(fù)雜,還是建議使用框架,畢竟功能更全。不過,在簡單的場景里,引入框架就沒有必要了。
本文以一個(gè)實(shí)際的例子,來說明微前端的一個(gè)具體應(yīng)用,可以展示出,這個(gè)理念本身非常有用,框架并不重要。
我個(gè)人創(chuàng)建了很多網(wǎng)站,比較雜也比較分散。如今嘗試把它們漸漸地聯(lián)結(jié)成一個(gè)整體,先想到的是讓它們復(fù)用一個(gè)統(tǒng)一的頁腳,于是首先將自己的個(gè)人主頁站點(diǎn)和我學(xué)習(xí)《計(jì)算機(jī)程序的構(gòu)造和解釋》時(shí)做的習(xí)題集站點(diǎn)加上統(tǒng)一的頁腳:
https://jeff-tian.jiwai.win
https://sicp.jiwai.win
這里詳解一下過程:
頁腳組件選型
看過一些,比如 bit.dev、contentful 站點(diǎn)的,后來還是覺得 rc-footer 最美觀,同時(shí)開發(fā)量最小。它是基于 React 的組件。
我想集成進(jìn)入的前兩個(gè)站點(diǎn),個(gè)人主頁站點(diǎn)是 Gatsby Js 的,前端使用到了 React;而那個(gè) sicp 站點(diǎn),則是基于 GitBook,是一個(gè)早就停止維護(hù)的開源框架,前端是基于 jQuery 的。因此想到集成進(jìn)個(gè)人主頁是很自然的,集成進(jìn)入 sicp 站點(diǎn)時(shí),可能會(huì)有一些挑戰(zhàn)。但是基于之前成功地在微信小程序里動(dòng)態(tài)嵌入了 React 組件,因此還是很有信心能夠搞定,畢竟在網(wǎng)頁里嵌入代碼,比起微信小程序來,要少很多限制。
【視頻】個(gè)人微信小程序如何動(dòng)態(tài)加載并運(yùn)行遠(yuǎn)程代碼(熱更新)?
用手機(jī)在微信小程序里寫 React 是一種什么體驗(yàn)?
頁腳開發(fā)
使用 rc-footer,基本上不需要什么開發(fā),填入數(shù)據(jù)就完成了。但是我將它發(fā)布在了 bit.dev,因?yàn)樗峁┝朔奖愎芾淼?Dashboard,也同時(shí)提供 npm 倉庫源服務(wù)。
https://bit.cloud/uniheart/experience/ui/uniheart-rich-footer
不過它還很新,版本號(hào)還在零點(diǎn)幾。感覺類似 Backstage,但是專注微前端托管,有了它,感覺 Storybook 都可以不用了。
嵌入個(gè)人主頁
因?yàn)槭?React 技術(shù)棧,所以只需要
yarn install @uniheart/experience.ui.uniheart-rich-footer要注意的是,以上 npm 包目前沒有發(fā)布到 npm registry,而是發(fā)布在了 bit.dev,所以需要在項(xiàng)目中增加 .npmrc 文件,并且將相關(guān)的 scope 寫入:
registry=https://registry.yarnpkg.com/@uniheart:registry=https://node.bit.dev@teambit:registry=https://node.bit.dev
然后在頁面里使用就行了。
import {UniheartRichFooter} from '@uniheart/experience.ui.uniheart-rich-footer'
嵌入 GitBook
這個(gè)要克服的問題略微多一些。首先,要知道 GitBook 提供了主題,而加入頁腳應(yīng)該在主題的布局中完成。所以,第一步是需要自己建立一個(gè)主題。
建立主題
我從官方的 default 主題源代碼倉庫 fork 了一個(gè),命名為 jeff-tian 主題:https://github.com/Jeff-Tian/theme-default。
引入 npm 包
這一步和嵌入個(gè)人主頁一樣,并且需要額外安裝 react 和 react dom。
增加 footer.js
這個(gè)文件就是將頁腳渲染出來的 js 代碼。由于不想再給已有的 GitBook Theme 工程增加更多依賴,所以沒有配置解析 jsx 語法的工具鏈。這時(shí)不像在個(gè)人主頁中那樣可以使用
同時(shí),由于宿主不是 React 技術(shù)環(huán)境,因此,需要手動(dòng)自行使用 ReactDOM.render 來將組件渲染在指定的位置。

修改布局文件
就是在合適的地方,增加一個(gè)placeholder,讓 footer.js 渲染后生效的一塊區(qū)域,我準(zhǔn)備渲染頁面,自然是在頁面最底部。在 layout.html 文件里,找到 body 標(biāo)簽,在結(jié)束前增加一點(diǎn)代碼:

解決打包問題
GitBook 主題的打包,需要運(yùn)行 src/build.sh 文件。我在運(yùn)行時(shí),碰到了錯(cuò)誤,看上去是不知道如何處理 css 文件。原來我在實(shí)現(xiàn)頁腳組件時(shí),引入了一個(gè) css 文件,而 build.sh 是使用的 browserify 進(jìn)行 js bundle,然后使用 uglify 進(jìn)行代碼壓縮。原來的 js 文件里不會(huì)引入 css,所以沒有問題。
為了解決 css 文件和 js 文件的混合 bundle,再次安裝一個(gè) npm 包:browserify-css,并修改 build.sh:
- node_modules/.bin/browserify src/js/theme/index.js | node_modules/.bin/uglifyjs -mc > _assets/website/theme.js+ node_modules/.bin/browserify -g browserify-css src/js/theme/index.js -o _assets/website/theme.js
為了簡化問題,沒有再折騰 uglify 對 css 的支持,代價(jià)是目前代碼文件會(huì)大一丟丟。
在 sicp 站點(diǎn)中引入 theme-jeff-tian
book.json 的 plugins 里增加:
{"plugins": [..."-theme-default","[email protected]",],...}
同時(shí)在 package.json 里增加 theme-jeff-tian 包的 dependency 項(xiàng),不然 book install 后,仍然會(huì)報(bào)找不到 theme-jeff-tian 的錯(cuò)誤。感覺 GitBook 這一塊兒的邏輯有點(diǎn)過于復(fù)雜了,如果細(xì)看,會(huì)發(fā)現(xiàn)它自己用了一個(gè)老版本的 npm 安裝 GitBook 插件,并單獨(dú)放在一個(gè)文件夾中。
..."dependencies": {"gitbook-plugin-theme-jeff-tian": "1.2.0"},..."scripts": {"build": "gitbook install && yarn install && book sm && gitbook build","serve": "gitbook serve"},...
完成
運(yùn)行 yarn build && yarn serve,效果完美。

總結(jié)
一、微前端的理念非常好,實(shí)現(xiàn)的框架相對沒那么重要。
二、React 組件并不要求宿主基于 React 技術(shù)棧。
三、jsx 只是語法糖,本質(zhì)上
四、由于 React 組件就是一個(gè)閉包函數(shù),所以要渲染它很容易,直接 ReactDOM.render() 就行了。這種隔離渲染真的是很爽,也是高內(nèi)聚低耦合的典范。

