Ukratko

Najvažnije iz članka

  • Web Componentsi omogućuju izgradnju inkapsuliranih, ponovno iskoristivih HTML elemenata koristeći web standarde, bez ovisnosti o specifičnom JS frameworku.
  • Vite.js je iznimno brz alat za razvoj i izgradnju, koji koristi izvorne ES module za instantno pokretanje servera i Hot Module Replacement (HMR).
  • Kombinacija Web Componentsa i Vite.js-a pruža optimalno razvojno iskustvo s brzim HMR-om i vrhunsku optimizaciju za produkciju putem Rollup bundlera.
  • Praktični primjer pokazuje kako inicijalizirati Vite.js projekt, kreirati TypeScript Web Komponentu, integrirati je u `index.html` i optimizirati za produkciju, naglašavajući prednosti poput CSS varijabli i event emitiranja.
Sadržaj članka
  1. Zašto Web Components?
  2. Nedostaci (i kako ih Vite.js rješava)
  3. Uvod u Vite.js: Sljedeća generacija alata za izgradnju
  4. Kombinacija Web Componentsa i Vite.js-a: Praktični primjer
  5. 1. Inicijalizacija Vite.js projekta
  6. 2. Kreiranje Web Komponente
  7. 3. Integracija u main.ts i index.html
  8. 4. Pokretanje razvojnog servera
  9. Optimizacija za produkciju s Vite.js-om
  10. Napredne teme i razmatranja
  11. Komponentne biblioteke
  12. Stencil.js
  13. CSS u Shadow DOM-u i CSS varijable
  14. Alati za testiranje
  15. Zaključak

Moderan web razvoj postao je kompleksniji nego ikad. S jedne strane, korisnici očekuju iznimno brze i responzivne aplikacije, dok s druge strane, developeri teže modularnosti, ponovnoj iskoristivosti koda i efikasnom razvojnom okruženju. U ovom članku istražit ćemo snažnu kombinaciju Web Componentsa i Vite.js-a – dva alata koja, kada se spoje, nude izvanredno rješenje za ove izazove, omogućujući brzi razvoj i optimalne performanse u produkciji.

Zašto Web Components?

Web Components su skup W3C standarda koji omogućuju izgradnju prilagođenih, inkapsuliranih i ponovno iskoristivih HTML elemenata. Oni predstavljaju temeljnu tehnologiju za kreiranje komponentnog sustava bez ovisnosti o specifičnom frameworku. Ključne prednosti Web Componentsa uključuju:

  • Enkapsulacija (Shadow DOM): Omogućuje izolaciju CSS-a i HTML-a unutar komponente, sprječavajući konflikte stilova i osiguravajući da se komponenta ponaša predvidljivo bez obzira na okruženje u kojem se koristi.
  • Ponovna iskoristivost: Jednom stvorena, komponenta se može koristiti bilo gdje u HTML-u, baš kao nativni HTML tag, čime se smanjuje dupliciranje koda i ubrzava razvoj.
  • Interoperabilnost: Budući da su temeljeni na web standardima, Web Componentsi rade s bilo kojim JavaScript frameworkom (React, Angular, Vue) ili bez njega, što ih čini vrlo fleksibilnim.
  • Standardizacija: Budući da su dio web standarda, ne ovise o životnom ciklusu pojedinog frameworka, osiguravajući dugoročnu stabilnost i kompatibilnost.

Primjer osnove Web Komponente:

class MyCustomButton extends HTMLElement {
  constructor() {
    super();
    const shadow = this.attachShadow({ mode: 'open' });
    const button = document.createElement('button');
    button.textContent = 'Klikni me!';
    button.style.backgroundColor = 'blue';
    button.style.color = 'white';
    button.style.padding = '10px 20px';
    button.style.border = 'none';
    button.style.borderRadius = '5px';
    button.addEventListener('click', () => {
      alert('Gumb je kliknut!');
    });
    shadow.appendChild(button);
  }

  connectedCallback() {
    console.log('Komponenta dodana u DOM');
  }

  disconnectedCallback() {
    console.log('Komponenta uklonjena iz DOM-a');
  }

  attributeChangedCallback(name, oldValue, newValue) {
    console.log(`Atribut ${name} promijenjen s ${oldValue} na ${newValue}`);
    // Ovdje se može ažurirati komponenta na temelju promjene atributa
  }
}

customElements.define('my-custom-button', MyCustomButton);

Nakon definiranja, ovu komponentu koristimo jednostavno u HTML-u:

<my-custom-button></my-custom-button>

Nedostaci (i kako ih Vite.js rješava)

Iako moćni, Web Componentsi sami po sebi ne pružaju kompletno razvojno okruženje. Neke od „nedostataka“ koje developeri često primjećuju, a koje Vite.js izvrsno rješava, uključuju:

  • Razvojno iskustvo (DevX): Ručno osvježavanje preglednika, spora kompilacija i nedostatak modernih dodataka mogu usporiti razvoj.
  • Bundle veličina: Bez optimizacije, pojedinačne komponente mogu biti veće nego što je potrebno.
  • Podrška za TypeScript/ESLint: Integracija ovih alata zahtijeva dodatnu konfiguraciju.
  • HMR (Hot Module Replacement): Dinamična zamjena modula bez potpunog osvježavanja stranice nije inherentno podržana.

Ovdje na scenu stupa Vite.js.

Uvod u Vite.js: Sljedeća generacija alata za izgradnju

Vite.js je iznimno brz alat za izgradnju i razvojno okruženje kreirano od strane Evana Youa (tvorac Vue.js-a). Njegova glavna prednost leži u iskorištavanju izvornih ES modula preglednika, eliminirajući potrebu za bundlanjem tijekom razvoja. To rezultira munjevitim pokretanjem servera i trenutačnim HMR-om.

Ključne značajke Vite.js-a:

  • Instant Server Start: Pokreće razvojni server u trenu.
  • HMR (Hot Module Replacement): Ažurira kod u pregledniku bez gubitka stanja aplikacije, pružajući izuzetno brzo razvojno iskustvo.
  • On-demand Compilation: Kompajlira samo ono što preglednik zatraži, umjesto da bundla cijelu aplikaciju.
  • Optimized Build: Koristi Rollup za produkcijski build, osiguravajući visoko optimizirane, minificirane i brze pakete.
  • Prva klasa podrška za TypeScript, JSX, CSS Preprocesore: Nema potrebe za složenom konfiguracijom.
  • Integrirana podrška za Web Workers i WASM: Jednostavno korištenje naprednih web tehnologija.

Kombinacija Web Componentsa i Vite.js-a: Praktični primjer

Pogledajmo kako možemo iskoristiti Vite.js za razvoj Web Componentsa.

1. Inicijalizacija Vite.js projekta

Prvo, kreirajte novi Vite projekt koristeći npm ili yarn:

npm create vite@latest my-web-components-app -- --template vanilla-ts
# ili
yarn create vite my-web-components-app --template vanilla-ts
# zatim
cd my-web-components-app
npm install
# ili
yarn install

Odabrali smo vanilla-ts (Vanilla JavaScript s TypeScriptom) jer nam pruža čistu osnovu i podršku za TypeScript, što je preporučljivo za veće projekte.

2. Kreiranje Web Komponente

Unutar src direktorija, kreirajte datoteku my-button.ts (ili .js ako ne koristite TypeScript):

// src/my-button.ts

// Definiramo CSS za komponentu u zasebnoj datoteci
// Vite će se pobrinuti za import i injektiranje stilova
import './my-button.css';

class MyCustomButton extends HTMLElement {
  constructor() {
    super();
    const shadowRoot = this.attachShadow({ mode: 'open' }); // 'open' ili 'closed'

    const template = document.createElement('template');
    template.innerHTML = `
      <style>
        /* Stilovi specifični za Shadow DOM (mogu se i importati, vidjeti my-button.css) */
        button {
          background-color: var(--button-bg, #007bff);
          color: var(--button-color, white);
          padding: 10px 20px;
          border: none;
          border-radius: 5px;
          cursor: pointer;
          font-size: 16px;
          transition: background-color 0.3s ease;
        }
        button:hover {
          background-color: var(--button-hover-bg, #0056b3);
        }
        button:active {
          background-color: var(--button-active-bg, #004085);
        }
      </style>
      <button><slot>Zadana oznaka</slot></button>
    `;

    shadowRoot.appendChild(template.content.cloneNode(true));

    // Dodavanje event listenera
    const button = shadowRoot.querySelector('button') as HTMLButtonElement;
    button.addEventListener('click', this._handleClick.bind(this));
  }

  // Definiranje promatračkih atributa
  static get observedAttributes() {
    return ['label', 'type'];
  }

  // Reagiranje na promjene atributa
  attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null) {
    if (oldValue === newValue) return;
    const button = this.shadowRoot?.querySelector('button');
    if (!button) return;

    switch (name) {
      case 'label':
        // Ako koristite <slot>, promjena label atributa neće direktno utjecati na sadržaj slota
        // Ovo bi se koristilo za internu logiku ili ako nemate slot
        // button.textContent = newValue || 'Zadana oznaka';
        break;
      case 'type':
        if (newValue === 'primary') {
          button.style.setProperty('--button-bg', '#28a745');
          button.style.setProperty('--button-hover-bg', '#218838');
        } else if (newValue === 'danger') {
          button.style.setProperty('--button-bg', '#dc3545');
          button.style.setProperty('--button-hover-bg', '#c82333');
        } else {
          // Reset na zadanu boju
          button.style.removeProperty('--button-bg');
          button.style.removeProperty('--button-hover-bg');
        }
        break;
    }
  }

  // Javna metoda komponente
  public clickMe() {
    this._handleClick();
  }

  private _handleClick() {
    console.log('Gumb je kliknut unutar komponente!');
    // Emitiranje prilagođenog događaja
    this.dispatchEvent(new CustomEvent('button-clicked', {
      bubbles: true,
      composed: true, // Omogućuje događaju da prođe kroz Shadow DOM granicu
      detail: { message: 'Hello from custom button!' }
    }));
  }
}

// Registracija komponente
customElements.define('my-custom-button', MyCustomButton);

declare global {
  interface HTMLElementTagNameMap {
    'my-custom-button': MyCustomButton;
  }
}
export default MyCustomButton;

U src/my-button.css možete definirati globalne stilove ili stilove koji se odnose na sam host element, iako je često bolje stilove unutar Shadow DOM-a držati u <style> tagu samog Shadow DOM-a ili ih importati:

/* src/my-button.css */
:host {
  display: inline-block;
  margin: 5px;
}

/* Primjer stila koji se odnosi na Shadow DOM varijable */
:host([type="primary"]) {
  /* Ove varijable će biti nadjačane u JS-u */
}

3. Integracija u main.ts i index.html

U src/main.ts importajte i registrirajte svoju komponentu (što smo već učinili s customElements.define u samoj komponenti):

// src/main.ts
import './style.css';
import './my-button'; // Samo importajte datoteku, ona će se registrirati sama

document.querySelector<HTMLDivElement>('#app')!.innerHTML = `
  <div>
    <h1>Web Components s Vite.js</h1>
    <p>Ovo je primjer korištenja custom komponente:</p>
    <my-custom-button label="Klikni me" type="primary">Klikni Primarni</my-custom-button>
    <my-custom-button type="danger">Opasnost!</my-custom-button>
    <my-custom-button>Zadani gumb</my-custom-button>
    <p>Pogledajte konzolu i kliknite gumbe!</p>
  </div>
`;

// Primjer slušanja događaja s custom komponente
document.addEventListener('button-clicked', (event: Event) => {
  const customEvent = event as CustomEvent;
  console.log('Uhvaćen custom događaj!', customEvent.detail);
});

U index.html (u korijenu projekta) osigurajte da imate <div id="app"></div> i da je main.ts ispravno uključen kao ES modul:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link type="image/svg+xml" href=""/vite.svg"" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite App</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src=""/src/main.ts"></script>"
  </body>
</html>

4. Pokretanje razvojnog servera

Sada pokrenite razvojni server:

npm run dev
# ili
yarn dev

Otvorite preglednik na prikazanoj URL adresi (npr. http://localhost:5173). Vidjet ćete svoju Web Komponentu, a sve promjene koje napravite u kodu bit će trenutno reflektirane zahvaljujući Vite.js HMR-u, bez osvježavanja stranice. Ovo značajno ubrzava razvojni proces.

Optimizacija za produkciju s Vite.js-om

Kada je razvoj završen, Vite.js stupa na snagu sa svojim optimiziranim build procesom. Pokretanjem build naredbe:

npm run build
# ili
yarn build

Vite.js će koristiti Rollup za bundlanje, minifikaciju i optimizaciju svih vaših datoteka (JavaScript, CSS, slike, itd.) u statičke assete spremne za produkciju. Rezultat je izuzetno malen, brz i efikasan set datoteka smješten u dist direktorij.

Ova optimizacija uključuje:

  • Tree Shaking: Uklanjanje neiskorištenog koda.
  • Code Splitting: Dijeljenje koda u manje chunckove koji se učitavaju po potrebi, smanjujući inicijalno učitavanje.
  • Minifikacija i kompresija: Smanjenje veličine datoteka za brži prijenos.
  • Asset Hashing: Korištenje heševa u nazivima datoteka za efikasno keširanje.

Za Web Components to znači da će Vite.js osigurati da su sve potrebne skripte, stilovi i predlošci spakirani na najefikasniji mogući način, bez obzira na to koliko komponenti imate.

Napredne teme i razmatranja

Komponentne biblioteke

Možete razviti cijele biblioteke Web Componentsa unutar jednog Vite.js projekta i zatim ih objaviti kao NPM pakete. Drugi projekti tada mogu jednostavno instalirati i koristiti te komponente, bez obzira jesu li ti projekti napravljeni s Reactom, Vueom ili čistim HTML-om/JS-om.

Stencil.js

Za složenije Web Components projekte, razmislite o korištenju alata poput Stencil.js. Stencil je alat za izradu Web Componentsa koji generira standardne Web Componentse, ali nudi naprednije značajke poput JSX-a za pisanje predložaka, state managementa, i optimizacije renderinga, slično modernim frameworkovima. Vite.js se može koristiti za bundlanje i optimizaciju Stencil projekata.

CSS u Shadow DOM-u i CSS varijable

Stiliziranje Web Componentsa može biti izazovno zbog enkapsulacije Shadow DOM-a. Najbolje prakse uključuju:

  • CSS Custom Properties (varijable): Omogućuju hostu komponente da 'gurne' stilove u Shadow DOM, nudeći fleksibilnost stiliziranja. Primjer je --button-bg u našem my-custom-button primjeru.
  • Dijeljeni stilovi: Globalni stilovi se mogu importati u Shadow DOM koristeći <link> ili @import unutar <style> taga, ali tada gube enkapsulaciju.
  • Kontekstualni stilovi: Korištenje :host selektora za stiliziranje samog host elementa komponente izvan Shadow DOM-a.

Alati za testiranje

Za testiranje Web Componentsa, možete koristiti standardne alate poput Jest-a, Vitest-a ili Web Test Runner-a, često u kombinaciji s @testing-library/dom za testiranje ponašanja DOM-a. Vite.js se dobro integrira s Vitest-om, pružajući brzo testiranje s HMR-om.

Zaključak

Web Componentsi su budućnost izgradnje UI komponenti na webu, nudeći standardiziranu, interoperabilnu i robusnu osnovu. Međutim, njihovo puno potencijalno iskorištavanje zahtijeva efikasno razvojno okruženje. Vite.js se pokazao kao savršen partner, pružajući munjevito brz razvoj, izvanredno HMR iskustvo i vrhunsku optimizaciju za produkciju. Kombinirajući ove dvije tehnologije, developeri mogu graditi brže, održivije i skalabilnije web aplikacije koje ispunjavaju najviše standarde performansi i korisničkog iskustva. Ako tražite modernu i efikasnu stack za razvoj komponentnih web aplikacija, kombinacija Web Componentsa i Vite.js-a je definitivno vrijedna istraživanja.

Izvori i dodatno čitanje

  1. MDN Web Components
  2. Vite.js Official Documentation
  3. Web Components Community
  4. Rollup.js for Bundling
B
Uredništvo portala

BAJT

Službeni autorski profil redakcije portala BAJT. Sadržaj priprema i provjerava uredništvo portala.