FDCon2019 第4屆中國前端開發者千人峯會 - 《Omi - Cross-Frameworks Framework》

你們好,此次給你們講下 Omi 框架 以及即將發佈的 Omim 你們有沒有數左邊的圖片裏有多少個 Omi?Omi 團隊很在乎這裏,特地數了下,有三個。Omi 團隊但願 Omi 之後在各大會議裏可以印刷得更加大一些。今天給你們帶來的主題是 《Omi - Cross-Frameworks Framework》,這也是 Omi 最新的 slogan。Omi 基於 Web Components 設計,和三大框架並非你死我活的關係,能夠很好的共存,無縫地集成,等聽完這個分享你們就能 get 到 Omi 的精髓。子標題的靈感來自於 preact 做者之前打算分享的《Push react to the limit》,原本 TFC2017 邀請了他,後來我的緣由他沒有來,固然他後來去了google,可能這個標題政治不正確:)。css

download-2

這是此次分享所包含的內容,不是目錄。會涉及到上面4部份內容。html

download-1

第一部分講下 Omi & Web Components。vue

download

Omi 準確來講是 5-6年前開始弄的,可是真正切換到 shadow dom v1 仍是2018年10月份左右,比 google 的 angular 更早使用 shadow dom v1。切換以後,獲得了一段快速發展的時期,一致延續到如今。當時是什麼初衷讓我開始打造 Omi?react

download-2

先來看看 react 的生命週期。當年看 React 的生命週期函數太長並且太多了,因此我要寫個生命週期函數更短且更少的框架,好比 Omi 的(install, uninstall, installed),並且貼合 npm 的命令:)。git

download-1

看下 Omi 中的生命週期,沒有與對應的 shouldComponentUpdate對應的生命週期函數,沒有 state 初始化、沒有 constructer 函數,生命週期函數命名更加端、生命週期函數更加少。大道至簡是真理,Omi 但願開發者不用手動優化 shouldComponentUpdate,怎麼作到的,後面 PPT 會講。github

download

打造 Omi 的初衷,還有一點很是重要的是,scoped css!scoped css 可讓組件的 css 選擇器更加簡潔,好比能夠直接寫 tag selector,若是組件裏只有一個 h1 的話。web

h1 {
  color: red;
}
複製代碼

這個 h1 不會污染組件外部的 h1,也不會污染組件內部的組件的 h1。chrome

download-5

來看下 ng。ng 支持四種模式typescript

  • 模擬 scope
  • shadow dom v0(不推薦,在將來版本去掉)
  • 無 scope
  • shadow dom v1

download-4

這是第一種模式,ng 模擬 scope 生成的 html 結構,每一個元素和子元素都會加上 scope attr。npm

download-3

這是第三種模式,html 結構什麼 attr 都不加。

download-2

這是第四種模式,也就是 shadow dom 的模式,和 Omi 同樣。

download-1

Omio 使用的也是 scope attr 模擬 shadow dom,這裏在內部實現的時候有兩點須要注意:

  • scoped attr 須要加到組件內部全部的子元素上,包括組件內部的組件自己
  • scoped attr 須要加到組件內部全部的子元素上,不包括組件內部的組件的子元素

有點繞,仔細體會下。即 scoped 到組件爲止,包括組件不進入組件。

download

這是 Omi 和 React 生成的 dom 結構對比。Omi 使用 shadow dom 進行隔離。

download

來看這張圖,很關鍵。這張圖來自 twiter。twiter 有個問題是 web components 能不能替換掉整個框架?stencil 團隊 show 出了這張圖,給 Omi 團隊帶來了很大的靈感。Omi 不只僅要自帶狀態管理、自帶組件體系替換掉整個框架,也能輸出單一的 custom elements 和任意框架集成。仔細看上圖,stencil 在各個框架中使用仍是有一些差別。

omi-inside-outside

Omi 作得更加完全!全部框架使用 custom elements 方式如出一轍!徹底不用記憶差別,只靠肌肉記憶編程!Omi 的組件變動也是徹底基於 setAttributeremoveAttribut,這種設計關鍵,由於其餘框架無論 vdom 仍是 real dom,最後都須要操做 dom 的 attribute,操做 attribute 就能進入到 Omi 的元素週期內部,這樣就無縫勾住了,在任意框架都能使用 Omi 寫的 custom elements。這裏有一點須要注意:

  • 若是使用 Omi 寫的 custom element 想要跨框架使用,必須聲明 static propTypes

這個其實也不麻煩,由於若是你使用 typescript 寫組件的話,自己就須要聲明 props 的類型,改爲大寫就能用在 propTypes 上。Omi 內部會根據聲明的類型,把使用組件時候傳入的字符串轉化爲對應的類型。

download

來看個實際的例子,這個 m-button 能夠在任意框架中使用。須要注意的是,能夠傳遞 json 字符串做爲 attr 給 m-button 內部使用。能夠看到上面的 icon 的 paths 並非標準的 json,可是沒有關係,omi 內部會轉成標準 json 再進行 JSON.parse 。並且你能夠直接使用 setAttribute 設置 json。

const btn = document.querySelector('m-button')
btn.setAttribute('icon',  {
  path: 'xx',
  color: 'xxx'
})
複製代碼

這裏須要注意一下,若是你再 react 中使用 Omi 的 element,並且須要傳遞 json 的話,能夠包裹一下 Omi.o,免得手動轉成字符串:

class TestOmiElement extends React.Component {
  render() {
    return (
    <div> <m-button icon={Omi.o({ path: 'xxx', color: 'xxxx' })}>omi button</m-button> </div> ); } } 複製代碼

download-9

這是 Omi 的初始化管線,前面說了 Omi 利用了 HTMLElement 鉤子函數 connectedCallback 監聽自定義元素插入到 dom 的行爲,這個行爲多是 Omi 觸發的,也能夠是 react、vue、ng 或原生 js 觸發的,觸發以後就進入了 Omi 的內部管線。

  • 建立 shadow dom
  • 建立 style 並插入到 shadow dom
  • 執行 render 建立虛擬 dom 並保存一份方便下次 update 的時候 diff
  • 根據虛擬 dom 生成 真實 dom 並插入到 shadow dom

很清晰簡明的管線。JSX 生成的虛擬 dom 會掛載在真實 dom 的 __omiattr_ 屬性上用於 dfii。 有沒有必有使用虛擬 dom?有必要!固然也能夠修改 h 函數保存真實 dom 用於 diff,主要區別在於內存開銷,速度差異不大。由於虛擬 dom 更輕量,屬性更少,都是必要屬性,因此用虛擬 dom。

download-8

看下 web components 最經常使用的三個生命週期函數。在 connectedCallback 會去執行 Omi 的 install,在 disconnectedCallback 會去執行 Omi 的 uninstall,最後一個 attributeChangedCallback 在 Omi 內部並無使用,由於 Omi 重寫了自定義元素的 setAttribute,從源頭上已經能夠監控到 attr change。

download-7

看下這段從 Omi 扒出來的源碼,Omi 重寫了 removeAttribute 和 setAttribute,這兩個方法被調用會自動觸發組件的更新,固然 Omi 也保留了原生的 removeAttribute 和 setAttribute,以 pure 開頭,用於 Omi 內部使用,由於內部 diff 和 apply diff 的時候並非須要每次都須要調用組件的 update。

download-6

看下這張圖,很關鍵。用過 react 的同窗都知道,react 性能優化的關鍵就是 shouldComponentUpdate,最被詬病的也是這個,不少開發者也吐槽這個鉤子函數,shouldComponentUpdate 也能夠配合不可變數據類型,直接進行引用地址比較,來決定組件是否須要更新。Omi 團隊一直在思考,這個東西可不能夠去掉,實時證實是能夠的。由於 Omi 自定義元素徹底基於字符串傳遞 props,不論是 boolean、string、number、json,都經過字符串傳遞,因此在進行組件更新以前,Omi 會進行一次淺比較,比較的結果決定是否更新,很是機智的作法。

download-5

在使用 web components 過程當中,最被你們詬病的就是樣式穿透問題。你們有些場景就是須要穿透組件怎麼辦?穿透不了就只能重寫組件了,或者修改組件的源碼。這個項目維護會帶來巨大的問題。Omi 爲了解決這個問題,支持屬性 css,用於覆蓋組件內部的 css 樣式。看上面的代碼,h1 是紅色的。

download-4

在父組件中使用my-element,經過傳遞 css,把 h1 顏色改爲 green 。並且還能夠動態修改組件內部的樣式,能夠 onClick 內部的代碼便知。

download-3

有的時候,咱們不知道咱們外部注入組件的選擇器權重是否足夠,咱們能夠經過加上 !important 保證必定覆蓋掉組件內部的樣式。

download-2

關於樣式,還有一點須要注意,font-fact 不能放在 shadow dom 中,否則不生效。固然這裏瀏覽器有差別,火狐能夠放在 shadow dom 中,google chrome 不行。因此咱們通常都放在外面用來兼容全部瀏覽器。

download-1

使用 font-face 的 font-family 的 class 定義必須放在 shadow dom 中,這個是有點割裂,可是仍是很好理解,由於 shadow dom 自己就是隔離的。

download

除了賦能 web 其餘框架,Omi 也提供了替換整個框架的解決方案,且看 store 體系。 store 體系是用於組件樹共享數據和邏輯,若是熟悉 react context api 的必定了解,可是 Omi store 不徹底同樣,store 上 data 的變動會產生一條 path,path 會去和組件上定義的 path 匹配,匹配上了就會進行更新,全部就達到了 局部 diff,局部更新 的目的。

download-5

看這是一個靜態聲明 path 的例子,固然也可使用 initUse 聲明動態 path。看上圖,計算屬性也能夠放在聲明裏。能夠這樣理解,store 是一個數據源頭,關於數據最後要怎麼預處理建議不要放在 store 裏,而是放在組件的 use 聲明裏,好比你要對字符串反轉,或者對數字平方什麼的,不建議放在 store 裏。

download-4

在 render 裏可使用 this.use 去訪問 store 的數據,固然也能夠經過 this.store.data.xx 的方式,後者書寫起來稍微麻煩一些。

download-3

這是命中的規則,第一列是由 proxy 的數據變動產生的 path,後者是組件定義的 path,只要命中一條就會更新組件。store 整個體系設計得很是簡單直接方便,沒有複雜的概念。

download-2

Omi 對 typescript 支持愈來愈好,後面 Omi 生態新增的全部組件、工具後者類庫都會使用 typescript 來書寫。上圖解釋了怎麼讓組件使用者可以在 typescript 或者智能提示。注意 Omi.props & ... 的目的是把 HTML 標準的屬性也集成到智能提示上,自己 Omi 寫的自定義元素就是標準的 HTMLElement。使用 JSX 寫 Omi 元素的時候,在 ts 的檢查會更加寬鬆,好比 tabindex="1",在 react ts 中必須寫成 tabIndex={1},Omi 順從 HTML 標籤,一段 HTML 直接粘貼到 render 函數中就能夠用,固然自閉合的標籤必須手動閉合下,好比 img。

download-1

在使用原生的 web components 的 customElements.define 的使用,體驗很很差。重複定義直接報錯,並且從報錯信息上也看不出是什麼元素重複定義了。

download

Omi 基於 customElement.define 封裝了 define 方法,有了前置的檢查邏輯,不報錯,只改告警,並且重複的名稱也會突出打印出來。

download-8

download-7

download-6

download-5

download-4

download-3

這是即將發佈的跨框架組件庫,一羣優秀的工程師正在加班加點趕進度,若是你感興趣也能夠加入進來,咱們一塊兒打造標準化的通用組件庫,框架無關、主題任意切換。

download-1

看上面這張圖,這是一個通用的組件,標準的自定義元素。能夠在 jsx 中使用,也能夠以標準的 html 的形式在任意框架(omi、react、vue、ng)中使用。將來 omim 提供的組件都會提供這兩種形式,方便任意形式的使用。

download-2

download

PPT以及演講內容以圖文的形式還原

待更新...

待更新...

相關文章
相關標籤/搜索