<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          想要開發(fā)組件庫?那你一定要提前了解一下這個(gè)神器

          共 27824字,需瀏覽 56分鐘

           ·

          2023-07-19 17:26



          轉(zhuǎn)自:前端學(xué)不動(dòng)


          相信很多人都有過制作組件庫的經(jīng)歷,也有一部分人做的組件庫需要適配各種不同的框架,或者相同框架的不同版本(如: Vue2 Vue3 等) 此時(shí)很多人就會(huì)選擇? Web Components ?來作為組件庫的技術(shù)棧。


          國(guó)內(nèi)用? Web Components ?做組件庫最知名的案例應(yīng)該就是凹凸實(shí)驗(yàn)室的? Taro UI ?了吧?凹凸團(tuán)隊(duì)曾說純?cè)Z法構(gòu)建?Web Components?過于繁瑣,希望能用聲明式語法來構(gòu)建?Web Components,所以選擇了?Stencil?這個(gè)框架/庫/編譯器(我也不知道叫啥好,就先叫框架吧。大家能明白意思就行,不必過于鉆牛角尖非要論證這個(gè)到底是個(gè)框架還是庫還是編譯器)

          Stencil

          但? Stencil ?生成出來的組件有虛擬? DOM ?及簡(jiǎn)易版? Diff ?算法,編譯出來的組件還是有點(diǎn)重。比方說我在?React?里用?Stencil?編譯出來的組件庫,React?本身就已經(jīng)有一套完善的虛擬?DOM?和?Diff?算法了,然而引入的組件庫卻包含了另一套虛擬?DOM?和?Diff?算法,這就很是浪費(fèi)。


          而且? Web Components ?也是有兼容性要求的:


          b7eadc8f3a543e423a1e29b501ee75eb.webp


          有些人公司的技術(shù)棧是? Vue 2 + 3 ,因?yàn)榭赡苡行╉?xiàng)目還是需要兼容低版本瀏覽器的,所以不得不用? Vue2 ,新項(xiàng)目可以用? Vue3 ,那么此時(shí)用? Web Components ?就有點(diǎn)不太合適了。


          Polyfill

          當(dāng)然有人可能會(huì)說不是有? Polyfill ?么?首先? Polyfill ?體積太大了,我們僅僅就是想用個(gè)組件庫而已,不至于再引入一個(gè)? Polyfill 。其次? Safari ?對(duì)? Web Components ?的支持有一點(diǎn)瑕疵, 從上圖可以看到? Safari ?雖然也是綠色,但是不是那種綠意盎然的綠,而是一種臟綠色。


          這種臟綠代表部分支持或者雖然支持但是有?bugSafari?屬于前者,當(dāng)然這個(gè)其實(shí)也有?Polyfill,張?chǎng)涡駨?GitHub?上?Fork?了一份然后進(jìn)行了改進(jìn)。

          不過還是太麻煩了點(diǎn),很多人用?Web Components?的目的僅僅只是為了能一套代碼適配多個(gè)框架而已。那么有沒有這樣一種方案:同樣也是只寫一套代碼,通過編譯的手段來達(dá)成相同的目的。

          Angular ?之父:那必須有啊!我這方案可比? Web Components ?好多了



          Mitosis 有絲分裂


          這個(gè)叫? Mitosis ?的項(xiàng)目出自? Angular ?之父之手,意思是有絲分裂:

          124534b1c38bc61a144b67a6ea4b575f.webp


          這個(gè)名字起的也非常符合它的職責(zé),一個(gè)變倆、倆變四、四變八、八變十六… 我們只需要編寫一套 DNA (代碼)就能為我們分裂出一大堆細(xì)胞(組件):


          9fc0a1916d7ffacfe96104d6292c2e66.webp


          我們?cè)賮砜纯此? GitHub ?上的標(biāo)語


          953400e8e97f495e562b2fb2df023330.webp

          Web Components:Write components once, run everywhere 這不是我的口號(hào)么?你特么搶我臺(tái)詞啊!

          Mitosis:我特么不僅要搶你臺(tái)詞,我還要把你的工作都給搶過來!

          91efec919c8da7ba3fbdebf8a7c54512.webp


          從口號(hào)中也可以看出,它與? Web Components ?的作用高度重合,但一個(gè)是運(yùn)行時(shí)方案,一個(gè)是編譯方案。這兩個(gè)方案各有利弊吧,隨著最近重編譯的框架迅速崛起,很多人都覺得這是一個(gè)更先進(jìn)的方案。之前在某問答平臺(tái)上看過這樣一條回答(關(guān)于 Svelte 的):


          60ec61557d3912380558c38d4b5952aa.webp


          當(dāng)然? Svelte ?是編譯成原生? DOM ?操作,既然能編譯成原生語法那為什么不能編譯成框架語法呢? Angular ?之父就是這么想的,我們一起來看一下? Mitosis ?的語法。



          簡(jiǎn) 簡(jiǎn)||介|紹


          我們點(diǎn)擊進(jìn)入?Mitosis?的官網(wǎng)?mitosis.builder.io,映入眼簾的是這樣的一幅界面:


          accf861960aeb8594277f30cda12989c.webp


          左邊就是我們寫的代碼(他們寫的 咱們啥也沒寫呢還),一股濃烈的? React ?味道撲鼻而來。右側(cè)就是編譯后的代碼,默認(rèn)是?Vue2,你看?Angular?他爸多體貼,不僅給咱們提供了?TSJS?選項(xiàng),甚至還能選擇編譯成?Options API?還是?Composition API


          afa3ee9f6676432fcd42787348c91b0d.webp


          Vue 的地位

          從這一個(gè)簡(jiǎn)單的小案例就能側(cè)面反映出如今? Vue ?的地位,身處 C 位啊家人們!那么多框架憑什么就? Vue ?排第一?我知道有人會(huì)說這肯定不是按照流行程度或者使用人數(shù)來排的名,因?yàn)槿绻凑者@個(gè)標(biāo)準(zhǔn)來排名的話肯定是? React ?排第一。


          這么說確實(shí)沒毛病,但我覺得? React ?之所以沒有排在? Vue ?前面的原因是因?yàn)樽髠?cè)編輯器代碼寫的本來就是濃濃的? React ?風(fēng),如果右側(cè)編譯區(qū)默認(rèn)還是? React ?的話那就是從? React ?編譯為? React


          7ed7fb4e60663dfd22a76003ad89cd4a.webp


          這有什么意思啊?就是多引入了一個(gè)? Styled JSX ?唄,這怎么能體現(xiàn)出? Mitosis ?的技術(shù)含量呢?所以才會(huì)把? React ?往后排一位,咱就說能編譯的框架有這么老多,在排除? React ?之后為啥就? Vue ?能排在最前面:


          170c601325e49afe7b22f74c43f00f88.webp


          我知道肯定又會(huì)有人說:你光在那凸顯右側(cè)編譯區(qū)? Vue ?的地位,怎么不說說左側(cè)編輯區(qū)沒有? Vue ?呢?人家可不光是只支持? JSX ,甚至還支持? Svelte


          63171a572612d5c03c4ddf90408645c9.webp


          如果? Vue ?真像你說的那么地位顯赫,那為什么只有? MITOSIS JSX SVELTOSIS ?怎么沒有? VUETOSIS ?也就是說為什么只能把? React ?編譯成? Vue ?卻不能反過來把? Vue ?編譯成? React ?呢?


          首先我覺得? Vue ?的單文件組件語法糖有點(diǎn)過多了,寫法也越來越多:

                    <template>
          ??<div/>
          <template>

          <script?lang="ts"?setup?generic="T extends?{?name:?string?}">
          ...
          </script>

          看上去就沒有? Svelte ?簡(jiǎn)潔,概念太多,需要你對(duì)? Vue ?有一定的了解,而且還有很多莫名其妙的全局變量語法糖:


                    <template>
          ??<div/>
          <template>

          <script?lang="ts"?setup?generic="T extends?{?name:?string?}">
          defineOptions({
          ??name:?'Foo'
          })

          defineExpose({?a,?b?})

          const?props?=?defineProps<{
          ??a:?string,
          ??b?:?number
          }>()

          const?emit?=?defineEmits<{
          ??(evt:?'update:modelValue',?value:?number):?void
          }>()

          const?slots?=?defineSlots<{
          ??default(props:?{?foo:?string;?bar:?number?}):?any
          }>()
          </script>


          反正就是越來越復(fù)雜,而且? Vue ?還在不停的更新迭代中,每次大更新就又往里塞語法糖,鬼知道? Vue3.4 3.5 3.6 、甚至是? 4.0 ?會(huì)變成什么鬼樣子!隨之而來的爭(zhēng)議也越來越大:


          25a0de3b0b16130d5a02b87d052dd5af.webp


          而? Svelte ?則要簡(jiǎn)潔的多,語法糖就一個(gè)? $: ,觸發(fā)更新也好記,只有等號(hào)? = ?才會(huì)觸發(fā)更新,對(duì)使用者而言不需要多么了解? Svelte ,只需要記住幾個(gè)簡(jiǎn)單的規(guī)則就可以迅速上手。


          JSX 同理

          而? JSX ?也是同理, JSX ?也不需要你多么了解? React ,大部分都是? JS ,你只需要了解一下在? JS ?里面寫? XML ?的規(guī)則就行,所以這才是左側(cè)編輯區(qū)僅支持? JSX ?與? Svelte ?的原因之一。


          當(dāng)然個(gè)人認(rèn)為這同樣也是? Svelte ?比? Vue ?更受(國(guó)外)新手歡迎的原因之一, Svelte ?在國(guó)外已經(jīng)搶走了原本屬于? Vue2 ?的一部分市場(chǎng)份額。

          培訓(xùn)班

          之前? Vue ?正是憑借簡(jiǎn)潔易用等優(yōu)勢(shì)在各大培訓(xùn)機(jī)構(gòu)里獲得了老師們的青睞, 老師講啥底下的學(xué)生就學(xué)啥,一批批 “ Vue ” 開發(fā)者大批量的涌入市場(chǎng),進(jìn)一步提升了? Vue ?的市場(chǎng)份額。但目前明顯是? Svelte ?更簡(jiǎn)單,只不過在中國(guó)沒人會(huì)招只會(huì)? Svelte ?的前端,所以為了就業(yè),培訓(xùn)班們估計(jì)也不會(huì)教。


          但如果? Vue ?的復(fù)雜程度超過了某個(gè)臨界點(diǎn)達(dá)到了培訓(xùn)班里大多數(shù)學(xué)生都學(xué)不會(huì)的那種程度或是學(xué)習(xí)周期過長(zhǎng)的話,就很有可能會(huì)給? Svelte ?、 Solid ?這類新秀一定的可乘之機(jī)。

          Vue2 也是 Vue

          當(dāng)然也有可能只教? Vue2 ???? 畢竟? Vue2 ?也是? Vue ,而且好學(xué)的多。學(xué)會(huì)了? Vue2 ?差不多也就“畢業(yè)”了,開始找工作了,到時(shí)候再讓他們?cè)诠ぷ髦忻? Vue3 ?吧。


          言歸正傳,我們先從? Mitosis ?的? README ?看起:


          6c2f7cb208cfa2a84177b239cbe89d5a.webp

          翻譯:我們正在積極尋找有興趣成為?Mitosis?貢獻(xiàn)者的人。鑒于它的編譯的范圍很廣,任何工程師都有很大的空間對(duì)項(xiàng)目產(chǎn)生巨大而持續(xù)的影響。我們投入大量時(shí)間幫助新手入職,并教他們?nèi)绾胃拇a庫(參見以下示例:#847、#372、#734)。如果有興趣,請(qǐng)查看我們的優(yōu)秀首期列表或聯(lián)系我們的Discord

          確實(shí)他們步子邁的很大,編譯的可不僅僅只是那幾個(gè)常見框架而已。現(xiàn)在正是缺人的時(shí)候,想在自己簡(jiǎn)歷上增添亮點(diǎn)的小伙伴們可得抓緊了!我們來看一下它到底能編譯成多少種技術(shù):


          69c981e486845a416aa5cd160554091f.webp


          • VUE

          • REACT

          • QWIK

          • ANGULAR

          • SVELTE

          • REACT NATIVE

          • RSC

          • SWIFT

          • SOLID

          • STENCIL

          • MARKO

          • PREACT

          • LIT

          • ALPINE.JS

          • WEB COMPONENTS

          • HTML

          • LIQUID

          • TEMPLATE

          • MITOSIS

          • JSON

          • BUILDER

          真不是我吹? Vue ?的地位,如果刨除掉? React ?這一特殊因素的話, Vue ?甚至都排在私心之前。什么是私心呢?給自己造出來的東西一個(gè)比較靠前的排序就叫私心, Angular ?之父對(duì)吧?


          當(dāng)然?Angular?本身就是三大框架之一,排序靠前也是應(yīng)該的。Qwik?這個(gè)就能看出私心來了,雖然是個(gè)很有潛力的超新星,但總體實(shí)力是比不上?Angular?的。Qwik?同樣也是?Angular?之父的最新力作(Angular之父牛逼),所以排在了?Angular?的前面。


          低代碼

          我們發(fā)現(xiàn)? Mitosis ?居然還可以編譯為? JSON ,編譯成其他框架其實(shí)也是根據(jù)生成的? JSON ?數(shù)據(jù)來進(jìn)行編譯的。 Mitosis ?還支持插件功能,你可以根據(jù)? JSON ?來生成任何你想要的東西。

          這對(duì)于最近幾年很火的低代碼平臺(tái)是個(gè)福音,Mitosis?所在的?Builder?就是做低代碼的,Mitosis?正是他們?cè)谧龅痛a時(shí)所創(chuàng)造的,目前也正在為他們的低代碼產(chǎn)品提供支持(所以不用擔(dān)心會(huì)出現(xiàn)賺不到錢不維護(hù)了的情況)


          Mitosis ?采用的是靜態(tài)? JSX ?來限制靈活性,不然的話根本沒法編譯:


          • 高情商:靜態(tài)?JSX

          • 低情商:閹割版?JSX


          721bbbc7213268e6e923f293fc46d0a0.webp


          閹割版 靜態(tài)版? JSX ?靈感源自于? Solid.js ,一個(gè)正常的組件將會(huì)被編譯為如下? JSON


          2f7548c0873fc629372e26210bfa093d.webp


          除了編寫組件庫之外, Mitosis ?同樣也可以用于編寫? SDK 。他們的新一代? SDK ?就是用? Mitosis ?寫的,并且還因?yàn)榻桓端俣群芸於艿搅速潛P(yáng):


          46d31d6948795dfdd5b8202fde7ebfc4.webp


          心動(dòng)不如馬上行動(dòng),接下來我們就按照官方文檔來創(chuàng)建一個(gè)? Mitosis ?項(xiàng)目。



          4dfe522938b41c30535cbe5954bfeef3.webp創(chuàng)建項(xiàng)目

          官網(wǎng)里沒有類似于? create-react-app ?或? create-vue ?這樣的工具,而是稍顯繁瑣,既然不好用那就是機(jī)會(huì)!大家可以立刻去給? create-vite ?提? PR ,讓它支持? Mitosis ,相信我,這玩意日后一定會(huì)火??


          它?README?寫的第一步就是:


          e78e9f22eeb71d083b1be7802c62ee2d.webp


          這真的很不人性化,因?yàn)檫@一看就是在一個(gè)已有項(xiàng)目里的操作,我們還得? npm init ?一個(gè)項(xiàng)目:


          0027dcefccdb155f8eb9fbd9c64e1420.webp

          然后? npm i @builder.io/mitosis-cli @builder.io/mitosis ,緊接著再在根目錄下創(chuàng)建一個(gè)? mitosis.config.js


          49cc00c1925ae8e4b602f94fa25d5380.webp


          在? mitosis.config.js ?里面寫上:


                    /**?@type?{import('@builder.io/mitosis').MitosisConfig}?*/
          module.exports?=?{
          ??files:?'src/**',
          ??targets:?['vue3',?'solid',?'svelte',?'react'],
          };


          然后再來安裝一下? TS npm i -D typescript ,隨即在根目錄下創(chuàng)建一個(gè)? tsconfig.json


                    {
          ??"compilerOptions":?{
          ????"strict":?true,
          ????"strictNullChecks":?true,
          ????"jsx":?"preserve",
          ????"jsxImportSource":?"@builder.io/mitosis"
          ??}
          }


          接下來咱們?cè)賮戆惭b一個(gè)? ESLint ?插件,由于? Mitosis ?的? JSX ?是 被閹割過 被靜態(tài)化過的? JSX ,所以必須要用? ESLint ?來限制你的靈活性。


          我們來看一下它都有哪些規(guī)則,首先就是? css-no-vars ?來限制你在? css ?屬性里寫表達(dá)式,哦對(duì)了,在? React ?里寫的? style ?屬性到了這里變成? css ?屬性了:

                    <button css={{?color:?a???'red'?:?'green'?}}?/>

          這段代碼在?React?里沒問題,但請(qǐng)記住,Mitosis?是一個(gè)編譯型框架,React?之所以能那么靈活就是因?yàn)樗勒踢\(yùn)行時(shí),我們必須寫的比較靜態(tài)一點(diǎn)才能被編譯出來一個(gè)具體值:

                    <button css={{?color:?'red'?}}?/>

          說實(shí)話其實(shí)還是蠻不爽的, style ?的值是動(dòng)態(tài)的這是一個(gè)很常見的需求,但在這里卻只能寫靜態(tài)值,這也是作為一個(gè)編譯型框架所不得不承受的缺點(diǎn)。再接下來的規(guī)則是? jsx-callback-arg-name ,這個(gè)規(guī)則可能會(huì)讓人比較費(fèi)解:


                    <button onClick={e?=>?console.log(e)}?/>


          這段代碼有毛病么?在? Mitosis ?里還真就有毛病!這個(gè)參數(shù)不能寫成? e ,要寫成別的(如 event ):


                    <button onClick={event?=>?console.log(event)}?/>


          寫成? e ?會(huì)影響編譯么?我不知道,我只想問一句? Why


          b4586c2ff1e51c4d121c121c5d2ab52c.webp

          接下來這個(gè)規(guī)則還算好接受一點(diǎn),叫?jsx-callback-arrow-function,顧名思義,跟?jsx?的回調(diào)函數(shù)以及箭頭函數(shù)有關(guān),只接受箭頭函數(shù)來作為回調(diào)函數(shù),其它值都不行:


                    //?這些都是反例:

          <button onClick={?function(event)?{}?}/>

          <button onClick={?null?}/>

          <button onClick={?"string"?}/>

          <button onClick={?1?}/>

          <button onClick={?true?}/>

          <button onClick={?{}?}/>

          <button onClick={?[]?}/>

          <button onBlur={?[]?}/>

          <button onChange={?[]?}/>


          必須箭頭函數(shù):

                    <button onClick={?event?=>?doSomething(event)?}/>

          <button onClick={?event?=>?doSomething()?}/>

          <button onClick={?event?=>?{}?}/>

          <button onClick={?()?=>?doSomething()?}/>

          再然后的條規(guī)則叫? no-assign-props-to-state ,一看名字就明白了,不能把? props ?分配給? state

                    import?{?useStore?}?from?'@builder.io/mitosis';

          export?default?function?MyComponent(props)?{
          ??const?state?=?useStore({?text:?props.text?});
          }

          在?Mitosis?中用?useStore?來表示響應(yīng)式值,你可以把它簡(jiǎn)單的理解為?Vue?的?reactive

                    import?{?reactive?}?from?'vue';

          const?props?=?defineProps(...)
          const?state?=?reactive({?text:?props.text?})

          下一條規(guī)則是不能在?state?里寫異步函數(shù)(no-async-methods-on-state):

                    //?反例:
          export?default?function?MyComponent()?{
          ??const?state?=?useStore({
          ????async?doSomethingAsync(event)?{
          ??????return;
          ????},
          ??});
          }

          那我們需要異步操作的話要怎么辦?可以用一個(gè)立即執(zhí)行函數(shù)來包裹一下:


                    export?default?function?MyComponent()?{
          ??const?state?=?useStore({
          ????doSomethingAsync(event)?{
          ??????void?(async?function?()?{
          ????????const?response?=?await?fetch();
          ??????})();
          ????},
          ??});
          }


          接下來這條規(guī)則會(huì)嚴(yán)重限制我們寫? jsx ?的靈活性,不能在? return ?出去的? jsx ?里寫條件判斷( no-conditional-logic-in-component-render )我們之前可能會(huì)經(jīng)常寫出這樣的代碼:

                    //?反例:
          export?default?function?MyComponent(props)?{
          ??if?(x?>?10)?return?<a?/>;
          ??else if?(x?<?5)?return?<b?/>;
          ??else return?<c?/>
          }

          在? Mitosis ?里可不行,你就只能有一個(gè)? return


                    //?反例:
          export?default?function?MyComponent(props)?{
          ??//?這個(gè) return 必須是靜態(tài)的:
          ??return?<a?/>
          }


          接下來是? state ?不能解構(gòu)( no-state-destructuring )跟? Vue ?一樣,因?yàn)樽罱K也會(huì)編譯成? Vue ?嘛:


                    export?default?function?MyComponent()?{
          ??const?state?=?useStore({?foo:?'1'?});
          ??//?不能解構(gòu):
          ??const?{?foo?}?=?state;
          }


          下面這個(gè)規(guī)則就比較令人費(fèi)解了,不能在? JSX ?里聲明變量( no-var-declaration-in-jsx ):


                    export?default?function?MyComponent(props)?{
          ??return?(
          ????<div>
          ??????{a.map((x)?=>?{
          ????????//?不能在這聲明變量:
          ????????const foo?=?'bar';
          ????????return?<span>{x}</span>;
          ??????})}
          ????</div>

          ??);
          }


          是不是有點(diǎn)扯蛋?但也不是說完全不能聲明變量,比方說解構(gòu)聲明就可以:


                    export?default?function?MyComponent(props)?{
          ??return?(
          ????<div
          ??????someProp={a.find((b)?=>
          ?{
          ????????//?解構(gòu)聲明的話可以:
          ????????const?{?x?}?=?b;
          ????????return x?<?1;
          ??????})}
          ????/>

          ??);
          }


          接下來這條規(guī)則也挺操蛋的,在組件里不能把一個(gè)變量賦值給另外一個(gè)變量:


                    //?以下全部都是反例:
          export?default?function?MyComponent(props)?{
          ??const?a?=?b;

          ??return?<div?/>;
          }

          let a;
          export default function MyComponent(props)?{
          ??a?=?b;

          ??return?<div?/>;
          }

          export default function MyComponent(props)?{
          ??let a;
          ??a?=?b;

          ??return?<div?/>;
          }


          下面這條規(guī)則對(duì)詞匯量不高的人來說很不友好,不能聲明一個(gè)與? state ?屬性同名的變量( no-var-name-same-as-state-property ):


                    import?{?useStore?}?from?'@builder.io/mitosis';

          export?default?function?MyComponent(props)?{
          ??const?state?=?useStore({
          ????a:?1,
          ??});

          ??//?這個(gè) a 和 stata.a 里的屬性重名了:
          ??const?a?=?1;

          ??return?<div?/>;
          }


          export function MyComponent(props)?{
          ??const state?=?useStore({
          ????a:?1,
          ??});

          ??function myFunction()?{
          ????//?哪怕說你聲明在其他作用域里也不行:
          ????const a?=?1;
          ??}

          ??return?<div?/>;
          }


          接下來這條規(guī)則是想把? JSX ?給變成一個(gè)單文件組件,因?yàn)槌丝梢詫?dǎo)出類型之外就只能用? export default ?默認(rèn)導(dǎo)出了( only-default-function-and-imports ):


                    //?
          export?default?function?MyComponent(props)?{
          ??return?<div?/>;
          }

          //?這么寫不行?只能?export default
          export const x?=?y;

          //?當(dāng)然如果你導(dǎo)出的是一個(gè) TS 類型的的話還是可以的:
          export type a?=?1;


          接下來就是和? Solid.js ?差不多的規(guī)則了,不要用三元表達(dá)式來進(jìn)行? JSX ?的條件判斷,取而代之的是? <Show> ?組件( prefer-show-over-ternary-operator ):


                    export?default?function?MyComponent(props)?{
          ??//?這么寫可不行:
          ??return?<div>{foo???<bar?/>?:?<baz?/>}</div>;

          ??//?要寫成這樣:
          ??return?(
          ????<div>
          ??????<Show?when={foo}>
          ????????<bar?/>
          ??????</Show>
          ??????<Show?when={!foo}>
          ????????<baz?/>
          ??????</Show>
          ????</div>

          ??);
          }


          下面的規(guī)則是為了糾正你從? React ?那里帶過來的習(xí)慣, ref ?不需要? .current ?屬性( ref-no-current ):


                    import?{?useRef?}?from?'@builder.io/mitosis';

          export?default?function?MyComponent(props)?{
          ??const?inputRef?=?useRef();

          ??const?myFn?=?()?=>?{
          ????//?不需要?.current
          ????inputRef.current.focus();
          ??};

          ??return?<div?/>;
          }


          最后一條規(guī)則是? useStore ?的返回值必須叫? state use-state-var-declarator )叫別的不行:

                    export?default?function?MyComponent(props)?{
          ??// useStore()?的返回值起名不是 state:
          ??const?a?=?useStore();
          ??//?必須寫成這樣:
          ??const?state?=?useStore();

          ??return?<div?/>;
          }

          還有就是? useState ?的返回值必須解構(gòu),也就是我們常用的一種寫法:


                    export?default?function?MyComponent(props)?{
          ??const?[name,?setName]?=?useState();
          ??return?<div?/>;
          }


          寫成這樣是萬萬不行的:


                    export?default?function?MyComponent(props)?{
          ??const?a?=?useState();
          ??return?<div?/>;
          }


          了解完這幾條規(guī)則之后我們就來安裝? ESLint ?插件吧:


                    npm i?-D [email protected]/eslint-plugin-mitosis

          安裝完成后再運(yùn)行一下? npx eslint --init ,接下來就是根據(jù)提示選擇自己想要的? eslint ?規(guī)范:


          02f1075f548dbadf8cbb3ac617a788ce.webp


          運(yùn)行完成后所生成的?.eslintrc.js?長(zhǎng)這樣:


          e3c5a2017af33679f16fab5ea50c9596.webp

          我們給它改成這樣:

                    module.exports?=?{
          ??env:?{
          ????browser:?true,
          ????es2021:?true,
          ????node:?true,
          ??},
          ??extends:?[
          ????'xo',
          ????'plugin:@builder.io/mitosis/recommended',
          ??],
          ??overrides:?[{
          ????extends:?['xo-typescript'],
          ????files:?['*.ts',?'*.tsx'],
          ??}],
          ??parserOptions:?{
          ????ecmaVersion:?'latest',
          ????sourceType:?'module',
          ????ecmaFeatures:?{jsx:?true},
          ??},
          ??rules:?{'@builder.io/mitosis/css-no-vars':?'error'},
          ??plugins:?['@builder.io/mitosis'],
          };

          接下來再來新建一個(gè)?src?文件夾,文件夾里新建一個(gè)?Component.lite.tsx,記住中間一定要有?.lite,如果你寫成?Component.tsx?那是萬萬不行的。

                    import?{useState}?from?'@builder.io/mitosis';

          export?default?function?MyComponent()?{
          ??const?[name,?setName]?=?useState('Alex');
          ??return?(
          ????<div>
          ??????<input
          ????????css={{
          ??????????color:?'red',
          ????????}}
          ????????value={name}
          ????????onChange={event?=>
          ?{
          ??????????setName(event.target.value);
          ????????}}
          ??????/>
          ??????Hello!?I can run in React,?Vue,?Solid,?or Liquid!
          ????</div>
          ??);
          }

          想要生成組件的話我們就要運(yùn)行一下: npm exec mitosis build ,接下來我們就可以看到命令行里:


          2cf72bbb3b3d8178f4c6da8f47687cb2.webp


          定睛一看,根目錄下多了個(gè)?output?文件夾:


          f2bc4327cc943295bb706dcdf15ec668.webp


          我們挨個(gè)來看下:

                    // React:
          import?*?as?React?from?"react";
          import?{?useState?}?from?"react";

          function?MyComponent(props)?{
          ??const?[name,?setName]?=?useState(()?=>?"Alex");
          ??return?(
          ????<>
          ??????<div>
          ????????<input
          ??????????className="input"
          ??????????value={name}
          ??????????onChange={(event)?=>?{
          ??????????setName(event.target.value);
          ??????????}}
          ????????/>
          ????????Hello!?I can run in React,?Vue,?Solid,?or Liquid!
          ??????</div>
          ??????<style jsx>{`
          ????????.input?{
          ??????????color:?red;
          ????????}
          ??????`}</style>
          ????</>
          ??);
          }

          export default MyComponent;
                    // Solid:
          import?{?createSignal?}?from?"solid-js";
          import?{?css?}?from?"solid-styled-components";

          function?MyComponent(props)?{
          ??const?[name,?setName]?=?createSignal("Alex");

          ??return?(
          ????<div>
          ??????<input
          ????????class={css({
          ??????????color:?"red",
          ????????})}
          ????????value={name()}
          ????????onInput={(event)?=>
          ?{
          ??????????setName(event.target.value);
          ????????}}
          ??????/>
          ??????Hello!?I can run in React,?Vue,?Solid,?or Liquid!
          ????</div>
          ??);
          }

          export default MyComponent;
                    <!-- Svelte -->
          <script>
          ??let?name?=?"Alex";
          </script>

          <div>
          ??<input?class="input"?bind:value={name}?/>
          ??Hello!?I can run in React,?Vue,?Solid,?or Liquid!
          </div>

          <style>
          ??.input?{
          ????color:?red;
          ??}
          </style>
                    <!-- Vue3 -->
          <template>
          ??<div>
          ????<input?class="input"?:value="name"?@input="name?=?$event.target.value"?/>
          ????Hello!?I can run in React,?Vue,?Solid,?or Liquid!
          ??</div>
          </template>

          <script>
          import?{?defineComponent?}?from?"vue";

          export?default?defineComponent({
          ??name:?"my-component",
          ??data()?{
          ????return?{?name:?"Alex"?};
          ??},
          });
          </script>

          <style?scoped>
          .input?{
          ??color:?red;
          }
          </style>

          是不是還挺智能的?不過有一點(diǎn)我很好奇,就是?React?的函數(shù)組件是每次更新都會(huì)執(zhí)行一次,也就是說如果我們寫成這樣:


          b139f838d69a14da4eca4b8048f16075.webp


          那么每次組件更新時(shí)都會(huì)?console.log?一遍,換算成?Vue?的話就相當(dāng)于:

                    //?偽代碼
          export?default?{
          ??updated?()?{
          ????console.log(this.name);
          ??}
          };

          那么會(huì)被編譯成這樣嗎?我們?cè)賮磉\(yùn)行一遍?npm exec mitosis build?試試。神奇的是,這次編譯把這個(gè)?console.log?直接編譯沒了,無論哪個(gè)框架的組件都沒有這段代碼,這也可以理解,為了讓所有框架行為一致,這些東西必須寫在生命周期里,那我們就:

                    import?{useState,?onMount}?from?'@builder.io/mitosis';

          export?default?function?MyComponent()?{
          ??const?[name,?setName]?=?useState('Alex');

          ??onMount(()?=>?{
          ????console.log(name);
          ??});

          ?return?(
          ????<div>
          ??????<input
          ????????css={{
          ??????????color:?'red',
          ????????}}
          ????????value={name}
          ????????onChange={event?=>
          ?{
          ??????????setName(event.target.value);
          ????????}}
          ??????/>
          ??????Hello!?I can run in React,?Vue,?Solid,?or Liquid!
          ????</div>
          ??);
          }

          最終編譯(只截取生命周期部分):

                    // React:
          useEffect(()?=>?{
          ??console.log(name);
          },?[]);
                    // Solid:
          onMount(()?=>?{
          ??console.log(name);
          });
                    // Svelte:
          onMount(()?=>?{
          ??console.log(name);
          });
                    //?Vue
          mounted()?{
          ??console.log(name);
          }

          Vue?和?Solid?這里就有點(diǎn)毛病了,因?yàn)榘蠢韥碚f應(yīng)該是這樣才對(duì):

          • Vue::console.log(this.name)

          • Solid:console.log(name())


          但它們?nèi)慷急痪幾g成了?console.log(name),實(shí)話實(shí)說,我覺得還是有點(diǎn)坑,哪怕說?Vue?這邊沒有這個(gè)?bug,但我在組件里除了聲明變量以外什么都不能寫,想寫邏輯的話就只能寫在生命周期內(nèi),不然就全給你刪了。


          缺陷

          缺陷就是語法限制的有點(diǎn)過多了,畢竟想要寫一套代碼編譯成差異巨大的各個(gè)框架組件的話,還是很難做到的。

          不過隨著這個(gè)項(xiàng)目的持續(xù)迭代,說不定這些問題都會(huì)有對(duì)應(yīng)的解決方案,不過目前來看不太推薦大家拿它來寫組件庫,文檔寫的也語焉不詳,有點(diǎn)坑…



          - EOF -


          4f4059035f29efe53815e68b43d625c3.webp

          加主頁君微信,不僅前端技能+1

          da5c30fe5bff28a75c8b13ce6da118a8.webpe7bf46de46976bc2f5f6054cb6c0cc63.webp

          主頁君日常還會(huì)在個(gè)人微信分享前端開發(fā)學(xué)習(xí)資源技術(shù)文章精選,不定期分享一些有意思的活動(dòng)崗位內(nèi)推以及如何用技術(shù)做業(yè)余項(xiàng)目

          加個(gè)微信,打開一扇窗



          推薦閱讀??點(diǎn)擊標(biāo)題可跳轉(zhuǎn)

          1、React 拖拽排序組件庫對(duì)比研究

          2、從零開始搭建一個(gè)屬于你自己的組件庫!

          3、看了 9 個(gè)開源的 Vue3 組件庫,發(fā)現(xiàn)了這些前端的流行趨勢(shì)


          覺得本文對(duì)你有幫助?請(qǐng)分享給更多人

          推薦關(guān)注「前端大全」,提升前端技能

          點(diǎn)贊和在看就是最大的支持 ??

          瀏覽 58
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  俺来也俺去也 | 先锋av在线资源 先锋av资源在线 | 大香蕉视频网站 | 中文字幕2区 | 午夜欧美 |