Vue ( 2 . x )、Storybook ( 5 . x )、ウェブコンポーネントe nient' altro



  • Intro
  • Cos'è Vue.js?
  • Cosa sono i Web Components?
  • Cos'è Storybook?

  • Definizione problema
  • Creazione progetto di test
  • Aggiunta di Storybook
  • Creazione di un Web Component
  • Problema con gli stili
  • Ipotesi sulla soluzione

  • implementazione di una soluzione
  • vue_config.js
  • Includere il web component nella story
  • Registrare il componente
  • Integrare l'interfaccia delle stories
  • Conclusioni e credits
  • イントロ

    cos 'θvueJS ?

    Vediamo cosa dice la documentazione:

    Vue (pronounced /vjuː/, like view) is a progressive framework for building user interfaces. Unlike other monolithic frameworks, Vue is designed from the ground up to be incrementally adoptable. The core library is focused on the view layer only, and is easy to pick up and integrate with other libraries or existing projects. On the other hand, Vue is also perfectly capable of powering sophisticated Single-Page Applications when used in combination with modern tooling and supporting libraries.
    [...]

    In atre parole, Vue è framework javascript da utilizzarsi nella realizzazione di frontend. Dalla sua ha la semplicità d'uso e di setup, il template code richiesto è minimo ed è comunque performante, tanto da essere riuscito a ritagliarsi nel tempo un proprio rispettabilissimo spazio accanto a framework decisamente molto più noti ed utilizzati (sì ovviamente sto parlando di Angular e React). Niente di più, niente di meno.

    ウェブコンポーネント?

    Se ne è scritto e tutt'ora se ne scrive (e spero se ne continuerà a scrivere) tantissimo, mi limiterò a fornire una piccola sintesi: i web components, in breve, non sono altro che componenti frontend i quali, una volta registrati dal browser e quindi da questo riconosciuti, possono essere usati come normali tag html con i propri attributi, parametri e comportamento peculiare.
    Possono essere definiti tramite classi in js vanilla o usando un framework che li supporti, nello specifico, come è facile intuire, in questo articolo si parlerà di web component definiti utilizzando Vue.js

    cos 'の物語物語?

    Storybook è un eccellente tool per il testing visuale di componenti UI, compatibile con tutti i maggiori framework js ed utilizzabile anche con js vanilla. Tutto quello che si deve fare è specificare quale componente renderizzare, fornire dei mock data e lasciare che storybook istanzi il nostro componente in un proprio iframe e il gioco è fatto. La criticità con vue nasce dalla difficoltà di poter istanziare semplici web components senza utilizzare altre dipendenze.


    問題の定義

    クレアチゾン英和対訳

    Creare web components con Vue non è un problema, tanto che la sua cli permette di specificare un target apposito per questo compito E、コンAlcuniアコーギルメンツは、可能性があります.
    Cerchiamo Ora di Andare Un Po ' pi de nel dettaglio , la Properura per United WEB Web Component in VueθDecisamente Banale , Partiamo da unnormal ale progetto vue :
    vue create vue-webcomponent-storybook-test
    
    La MIA ConfigativiOneカスタムは、Staata Typescript、Babel、SCSS(Dart Sass)E基本的なリンダを保存します.
    アルベラトゥーラ・ディストゥー・ティポの「サプリメント」について
    ├── dist
    ├── node_modules
    ├── public
    │   ├── favicon.ico
    │   └── index.html
    ├── src
    │   ├── assets
    │   │   └── logo.png
    │   ├── components
    │   │   └── HelloWorld.vue
    │   ├── App.vue
    │   ├── main.ts
    │   ├── shims-tsx.d.ts
    │   └── shims-vue.d.ts
    ├── .gitignore
    ├── babel.config.js
    ├── package.json
    ├── README.md
    ├── tsconfig.json
    ├── vue.config.js
    └── yarn.lock
    
    アントニオ・リサイコ『ダ・ターターレ』yarn serve , Potremo Vedereラノストラアプリコンil成分HelloWorld.vue ディーテスト、運賃ベラモストーdi se suhttp://localhost:8080/ .

    Aggiuntaディ物語帳

    Il secondo passo consiste nell'installare Storybook Attraverso ILプラグインマネージャdi vue , anche qui l operoperione non - th particolarmente hemgnativa :
    vue add storybook
    
    <書評> Aggiunger Tale Alcuni File E Cartelle :
    ├── config
    │   └── storybook
    │       └── storybook.js
    ├── dist
    ├── node_modules
    ├── public
    │   ├── favicon.ico
    │   └── index.html
    ├── src
    │   ├── assets
    │   │   └── logo.png
    │   ├── components
    │   │   ├── Helloworld.vue
    │   │   └── MyButton.vue
    │   ├── stories
    │   │   ├── index.stories.js
    │   │   └── index.stories.mdx
    │   ├── App.vue
    │   ├── main.ts
    │   ├── shims-tsx.d.ts
    │   └── shims-vue.d.ts
    ├── .gitignore
    ├── babel.config.js
    ├── package.json
    ├── README.md
    ├── tsconfig.json
    ├── vue.config.js
    └── yarn.lock
    
    <研究ノート> IL - Componenttesrc/components/MyButton.vue Eラストーリーsrc/stories/index.stories.mdx , ノンサルノンササリアルノストロプロゲート.
    オールインターノディsrc/stories/index.stories.js IL NOSTO構成要素につきCreiamo una話App.vue :
    < div >
    <原著論文> Lanciando ILタスクstorybook:serve , <研究ノート>第二次世界大戦中におけるシュテイ書について
    <> P >
    < div class ="ハイライト"
    npm run storybook:serve
    
    < P >


    < p >( <研究ノート>)p >
    < H 3 >

    ウェブコンポーネント

    Il secondo passo consiste nel wrappare il nostro componente (lavoreremo con il componente root di default, App.vue , questo ci permetterà di vedere l'inclusione di altri componenti e come si comportano i loro stili, tutto è ovviamente replicabile per qualunque componente) all'interno di una classe che estende HTMLElement (link approfondimento), questo non verrà fatto direttamente da noi, ma attraverso una api fornita da Vue. Alla fine di questo step il file main.ts avrà questo aspetto:

    customElements.define fa parte dell'api js che materialmente permette di registrare il nostro componente al browser con il tag name my-web-component .
    Una piccola nota, se usate typescript come il sottoscritto, potreste dover aggiungere al file shim-vue.d.ts la definizione del modulo per @vue/web-component-wrapper :

    declare module '@vue/web-component-wrapper';
    

    Questo per evitare l'errore Could not find a declaration file for module '@vue/web-component-wrapper'. che su ide come IntelliJ e simili potrebbe essere apparso, strano non sia presente un d.ts già preinstallato che risolve il problema.

    A questo punto nell' index.html del nostro progetto (in public/index.html ) dovremo liberarci del root component predefinito (il div con id="app" ) e sostituirlo con il nostro componente appena registrato. Il nostro index, quindi, sarà:


    Gliスティリーの問題

    Lanciando ora il comando yarn serve vedremo in nostro componente funzionare alla grande, no?


    <高橋潤子>p >
    <現地通信>非自称でma .ダヴDiavoloソフィニッシュgliスティリー?p >
    < p > IL Guaioθche vue ha Inluso gli stili el tag<head> Della Paginaは、Farebbe Normalmenteを得ます、ma il nostro component enls - rinchiuso dentro ad unoシャドーDOMhttps://w3c.github.io/webcomponents/spec/shadow/ ), <研究ノート>不確実性のための生命現象に関する一考察p >
    ストーリーストーリーインシデント?リトルビッグプラネット™2でアップロードbhe le cose non migliorano di molto .イルフィノindex.stories.js


    < div class ="LagagCount - gig - Link - tag "
    "スクリプトのID "https://gist.github.com/lucabro81/7bfddff6e9548071648d50cf0034a2e4.js//>
    < div >
    <資料>利用者のための著作権についてmain.ts ), <研究ノート>レンダーサZarlo , MAノンソノApplati
    < P >


    < hr/>
    < H >>

    イポッティスルルシジオン

    Una possibile soluzione è descritta qui , クェンタ・ペロシワンshodowMode ディvue-loader セトタムAfalse ディdefault , Da Qui il cursioso comportamente riscontratoQuesto punto mettere社true Quella Pervet et dovrebbe risolvere il problem emap >
    < H 3 >

    ValueConfig.js

    Tutto ciò di cui abbiamo bisogno ora è il file vue.config.js ネラルートデルノストロプロゲート;<翻訳>p >
    < p > :コサ・リヒョウのために
    <> P >
    < div class ="ハイライト"

    vue inspect
    
    <研究ノート>リシュタタト・アソムマイヤー『Questo』
    < div class ="LagagCount - gig - Link - tag "
    "スクリプトのID "https://gist.github.com/lucabro81/dc2cf337b78afb2dd539a23381832ec6.js//>
    < div >
    <判例研究>エッセイロの場合:アルセコンコメンティ・インターセショナルティについて
    <> P >
    < div class ="ハイライト"
    /* config.module.rule('css').oneOf('vue').use('vue-style-loader') */
    
    <資料>コンプライアンスの構成要素についてwebpack-chain ( https://github.com/neutrinojs/webpack-chain ) ツール・ユーティリティーは、WebPackにつきファイルStaSetazioneをファイルします.ヴィスト・シュ・ゲ・ゲイ・トゥ・インストゥート・エヌ・ノストラ・プロゲート,『可能性のあるもの』p >
    <研究>第二次大戦中における相互行為の構成と構成shadowmode: false , <研究ノート> P . E . P .
    < div class ="LagagCount - gig - Link - tag "
    "スクリプトのID "https://gist.github.com/lucabro81/126ddadada54a9e44cc84ffdbf5712c6.js//>
    < div >
    < p > Ora , Ci - Cone - che che mettiamo nelvue_config.js <研究ノート>コンチェルト・ダ・ウェッパックE .インテグレイト・ネル・プロッツォの編纂について
    < div class ="LagagCount - gig - Link - tag "
    "スクリプトのID "https://gist.github.com/lucabro81/e5a2c9f6b252350828ff2adffe47ec6f.js//>
    < div >
    クエスチススクリプトaggiungeshadowMode=false OVUNQUE SIA必需品E permette A Properties Con - Compilazione , Finalmente Quello che si Avr - R SAR An Web Webコンポーネントcorrettamente renderizzato che inccapsula tutti i suoi stili :< p >
    < P >


    < H 3 >

    Illudle ILウェブコンポーネントネラストーリー)

    Se lanciamo storybook ora, vedremo che anche lì il nostro componente sarà corretamente renderizzato, tuttavia l'api di storybook in questo caso non ci aiuta: come facciamo a passare dati al nostro componente in modo efficiente? Se questi dati sono oggetti complessi? Come si può interfacciare il nostro web component con l'api esposta dall'addon knobs?

    Ok andiamo con ordine:


    ILコンポーネントの登録

    Questa è facile, ogni componente deve essere registrato come abbbiamo detto, un a possibilità è implementare una funzione che controlli se già il componetne non sia stato registrato e in caso contrario proceda di conseguenza, qualcosa del genere:

    Davvero molto semplice, gli elementi non registrati hanno come constructor HTMLElement() , è sufficente fare un check e il gioco è fatto.

    Successivamente, il componente va registrato:

    anche qui nulla di nuovo, la procedura è quella vista poco sopra, soltanto chiusa dentro una funzione.


    インテグラ・インタフェース

    Ora dobbiamo fare in modo di poter usare l' addon-knobs per poter passare dati al nostro componente e renderli reattivi ai cambiamenti che possiamo fare durante i test, la mia soluzione è stata costruire una funzione che restituisse un componente e succesivamente ne recuperasse il riferimento per potergli passare eventuali dati:

    Cerchiamo di capire cosa questo script effettivamente fa:

    export const webComponentWrapper = ({props, template}) => {
    ...
    

    In ingresso ci si aspetta un oggetto, per esempio:

    props: {
      test: [
        ['test', true, 'GROUP-ID1'],
        boolean
      ],
    },
    template: '<test-component></test-component>'
    

    formato dalla proprietà props che sarà un altro oggetto, i suoi elementi avranno come chiave il nome della proprietà del nostro componente e per valore un array dove il primo elemento sarà un ulteriore array formato da

    • nome proprietà (sì c'è un po' di ridondanza di cui è possibile liberarsi),
    • valore che si dovrà considerare
    • e l'etichetta che vogliamo dare al gruppo di dati di quello specifico knob.

    Il secondo valore, invece, la funzione dell'addon knobs che verrà utilizzata per trattare quello specifico tipo di dato (in questo caso boolean ).
    template invece è una stringa che rappresenta il nostro componente e quello che contiene.


    ...
    const id = generateRandomNumber(0, 10 ** 16);
    ...
    

    Qui generiamo un id casuale che verrà utilizzato poi per applicarlo al componente e recuperarne il riferimento, io ho creato una funzione apposta, ma in effetti può essere benissimo un timestamp qualunque.


    ...
    for (const key in props) {
      if (Object.hasOwnProperty.call(props, key)) {
    
        const old = key + 'Old' + id;
        const value = key + 'Value' + id;
    
        props[old] = null;
        props[value] = () => (props[old] !== null) ? props[old] : props[key][0][1];
      }
    }
    ...
    

    Ora cominciamo a lavorare sui dati da passare al componente: prima di tutto prendiamo la proprietà props e ne scorriamo il contenuto, per ogni elemento preso in considerazione, lo arricchiamo di altre due proprietà (le variabili old e value ), alla prima diamo null alla seconda una funzione che ritornerà il vecchio valore ( old ) o quello di 'default' passato assieme alle proprietà (per capirci, il valore true nel ['test', true, 'GROUP-ID1'] di cui abbiamo parlato più su) a seconda che il vecchio valore esista o meno.

    Ogni volta che in Storybook selezioniamo un certo componente questo viene reinizializzato, con questo sistema riusciamo a passare sempre l'ultimo valore usato nei knobs, diversamente ritornando su un componente perderemmo le modifiche fatte durante i nostri test e vedremmo sempre il primo valore passato.


    return () => {
      setTimeout(() => {
    
        const root = document.getElementById(id.toString());
        const old = 'Old' + id;
        const value = 'Value' + id;
    
        for (const key in props) {
    
          if (Object.prototype.hasOwnProperty.call(props, key) && !key.includes(old) && !key.includes(value)) {
    
            const knobsParams = props[key][0];
            const knobsFunction = props[key][1];
            const tagElem = props[key][2];
    
            knobsParams[1] = props[key + value]();
            props[key + old] = props[key][1](...knobsParams);
    
            if (tagElem) {
              const elems = root.getElementsByTagName(tagElem)
              elems.forEach((item) => {
                item[key] = props[key + old];
              })
            }
            else {
              root[key] = props[key + old];
            }
          }
        }
    
      });
    
      return newTemplate;
    }
    

    la funzione ritornata è quella che verrà eseguita da Storybook ogni volta che si selezionerà quel determinato componente.

    Prima che questa ritorni il template (nulla più che una stringa del tipo <my-web-component></my-web-component> ), si esegue un timeout privo dei milliscondi di durata, questo permette all'handler di rientare nella coda del loop event appena sarà possibile (più informazioni qui), in questo caso appena il template diventa un elemento della pagina.

    Viene recuperato il riferimento del componente tramite l'id calcolato prima, dopo di che vengono recuperati i dati dall'oggetto passato alla funzione e passati al componente. Come detto prima, il dato viene salvato nella proprietà aggiunta prima (qui props[key + old] = props[key][1](...knobsParams); ).



    結論Iクレジット

    E questo è quanto, mettendo tutto assieme, si riesce ad avere un progetto Vue per testare web components (e non solo normali classi Vue) con Storybook e il dev server incluso. Qui 完全なe - funzionanteをテストしてください.p >
    <堀田>
    <ウル>

  • Get started with Vue web components
  • Create & Publish Web Components With Vue CLI 3
  • How to define style within a web component?
  • What is Vue Loader?
  • Configuration Reference
  • How to get list of registered custom elements
  • < ull >