1. Introduzione
Che cos'è Lit
Lit è una semplice libreria per creare componenti web veloci e leggeri che funzionano in qualsiasi framework o senza alcun framework. Con Lit puoi creare componenti, applicazioni, sistemi di progettazione condivisibili e altro ancora.
Obiettivi didattici
Come tradurre diversi concetti di React in Lit, ad esempio:
- JSX e modelli
- Componenti e accessori
- Stato e ciclo di vita
- Hooks
- Bambini
- Riferimenti
- Stato della mediazione
Cosa creerai
Al termine di questo codelab, potrai convertire i concetti dei componenti React nei relativi analoghi Lit.
Che cosa ti serve
- La versione più recente di Chrome, Safari, Firefox o Edge.
- Conoscenza di HTML, CSS, JavaScript e Chrome DevTools.
- Conoscenza di React
- (Avanzato) Se vuoi un'esperienza di sviluppo ottimale, scarica VS Code. Avrai bisogno anche di lit-plugin per VS Code e NPM.
2. Lit e React
I concetti e le funzionalità principali di Lit sono simili a quelli di React per molti aspetti, ma Lit presenta anche alcune differenze e caratteristiche distintive:
È piccolo
Lit è minuscolo: si riduce a circa 5 kB compressi e con gzip rispetto ai più di 40 kB di React + ReactDOM.
È veloce
Nei benchmark pubblici che confrontano il sistema di creazione di modelli di Lit, lit-html, con il VDOM di React, lit-html risulta 8-10% più veloce di React nel peggiore dei casi e più del 50% più veloce nei casi d'uso più comuni.
LitElement (la classe di base dei componenti di Lit) aggiunge un overhead minimo a lit-html, ma supera le prestazioni di React del 16-30% se si confrontano le funzionalità dei componenti, come l'utilizzo della memoria, l'interazione e i tempi di avvio.
Non richiede una build
Con le nuove funzionalità del browser, come i moduli ES e i valori letterali dei modelli con tag, Lit non richiede la compilazione. Ciò significa che gli ambienti di sviluppo possono essere configurati con un tag script + un browser + un server e il gioco è fatto.
Con i moduli ES e le CDN moderne come Skypack o UNPKG, potresti non aver nemmeno bisogno di NPM per iniziare.
Tuttavia, se vuoi, puoi comunque creare e ottimizzare il codice Lit. Il recente consolidamento degli sviluppatori intorno ai moduli ES nativi è stato positivo per Lit: Lit è semplicemente JavaScript normale e non sono necessarie interfacce a riga di comando specifiche per il framework o la gestione delle build.
Indipendente dal framework
I componenti di Lit sono basati su una serie di standard web chiamati componenti web. Ciò significa che la creazione di un componente in Lit funzionerà nei framework attuali e futuri. Se supporta gli elementi HTML, supporta i componenti web.
Gli unici problemi dell'interoperabilità del framework si verificano quando i framework hanno un supporto restrittivo per il DOM. React è uno di questi framework, ma consente di uscire tramite i riferimenti e i riferimenti in React non sono un'esperienza ottimale per gli sviluppatori.
Il team di Lit sta lavorando a un progetto sperimentale chiamato @lit-labs/react
che analizzerà automaticamente i componenti Lit e genererà un wrapper React in modo che tu non debba usare i riferimenti.
Inoltre, Custom Elements Everywhere mostra i framework e le librerie che si integrano bene con gli elementi personalizzati.
Supporto TypeScript all'avanguardia
Sebbene sia possibile scrivere tutto il codice Lit in JavaScript, Lit è scritto in TypeScript e il team di Lit consiglia agli sviluppatori di utilizzare anche TypeScript.
Il team di Lit sta collaborando con la community Lit per aiutare a gestire progetti che integrano il controllo del tipo di TypeScript e l’Intellisense nei modelli Lit sia durante lo sviluppo che la creazione con lit-analyzer
e lit-plugin
.
Gli strumenti per sviluppatori sono integrati nel browser
I componenti Lit sono solo elementi HTML nel DOM. Ciò significa che per ispezionare i componenti non devi installare strumenti o estensioni per il browser.
Puoi semplicemente aprire gli strumenti per gli sviluppatori, selezionare un elemento ed esplorarne le proprietà o lo stato.
È progettato per il rendering lato server (SSR)
Lit 2 è stato creato pensando al supporto di SSR. Al momento della stesura di questo codelab, il team di Lit non ha ancora rilasciato gli strumenti SSR in un formato stabile, ma il team di Lit ha già implementato componenti sottoposti a rendering lato server nei prodotti Google e ha testato SSR nelle applicazioni React. Il team di Lit prevede di rilasciare questi strumenti esternamente su GitHub a breve.
Nel frattempo, puoi seguire l'avanzamento del team di Lit qui.
La partecipazione è bassa
Lit non richiede un impegno significativo per l'utilizzo. Puoi creare componenti in Lit e aggiungerli al tuo progetto esistente. Se non ti piacciono, non devi convertire l'intera app contemporaneamente, dato che i componenti web funzionano in altri framework.
Hai creato un'intera app in Lit e vuoi passare a qualcos'altro? Bene, puoi posizionare la tua applicazione Lit attuale all'interno del nuovo framework ed eseguire la migrazione di ciò che vuoi ai componenti del nuovo framework.
Inoltre, molti framework moderni supportano l'output nei componenti web, il che significa che in genere possono essere inseriti in un elemento Lit.
3. Configurazione ed esplorazione di Playground
Questo codelab può essere eseguito in due modi:
- Puoi farlo interamente online, nel browser
- (Avanzato) Puoi farlo sulla tua macchina locale utilizzando VS Code
Accedere al codice
Durante il codelab ci saranno link a Lit Playground come questo:
Il playground è una sandbox di codice che viene eseguita completamente nel browser. Può compilare ed eseguire file TypeScript e JavaScript e può anche risolvere automaticamente le importazioni nei moduli dei nodi, ad es.
// before
import './my-file.js';
import 'lit';
// after
import './my-file.js';
import 'https://cdn.skypack.dev/lit';
Puoi svolgere l'intero tutorial nella sandbox Lit, utilizzando questi checkpoint come punti di partenza. Se utilizzi VS Code, puoi utilizzare questi punti di controllo per scaricare il codice iniziale per qualsiasi passaggio e utilizzarli per verificare il tuo lavoro.
Esplorazione dell'UI di un parco giochi illuminato
Lo screenshot dell'interfaccia utente di Lit Playground evidenzia le sezioni che utilizzerai in questo codelab.
- Selettore file. Nota il pulsante Più…
- Editor di file.
- Anteprima del codice.
- Pulsante Ricarica.
- Pulsante di download.
Configurazione VS Code (avanzata)
Ecco i vantaggi dell'utilizzo di questa configurazione di VS Code:
- Controllo del tipo di modello
- IntelliSense e compilazione automatica dei modelli
Se hai già installato NPM, VS Code (con il plug-in lit-plugin) e sai come utilizzare tale ambiente, puoi semplicemente scaricare e avviare questi progetti procedendo nel seguente modo:
- Premi il pulsante di download
- Estrai i contenuti del file tar in una directory
- (In caso di risoluzione del problema) configura un tsconfig rapido che generi moduli es ed es2015+
- Installa un server di sviluppo in grado di risolvere gli specificatori di moduli bare (il team di Lit consiglia @web/dev-server)
- Ecco un esempio
package.json
- Ecco un esempio
- Esegui il server di sviluppo e apri il browser (se utilizzi @web/dev-server puoi utilizzare
npx web-dev-server --node-resolve --watch --open
)- Se utilizzi l'esempio
package.json
, utilizzanpm run dev
- Se utilizzi l'esempio
4. JSX e modelli
In questa sezione apprenderai le nozioni di base sui modelli in Lit.
Modelli JSX e Lit
JSX è un'estensione di sintassi di JavaScript che consente agli utenti di React di scrivere facilmente modelli nel codice JavaScript. I modelli di lite hanno uno scopo simile, ovvero esprimere l'interfaccia utente di un componente in funzione del suo stato.
Sintassi di base
In React, il codice JSX di un messaggio di benvenuto sarebbe simile al seguente:
import 'react';
import ReactDOM from 'react-dom';
const name = 'Josh Perez';
const element = (
<>
<h1>Hello, {name}</h1>
<div>How are you?</div>
</>
);
ReactDOM.render(
element,
mountNode
);
Nell'esempio riportato sopra sono presenti due elementi e una variabile "name" inclusa. In Lit, svolgi i seguenti passaggi:
import {html, render} from 'lit';
const name = 'Josh Perez';
const element = html`
<h1>Hello, ${name}</h1>
<div>How are you?</div>`;
render(
element,
mountNode
);
Tieni presente che i modelli Lit non richiedono un frammento React per raggruppare più elementi nei modelli.
In Lit, i modelli sono racchiusi in un html
modello con tag LITeral, da cui deriva il nome di Lit.
Valori del modello
I modelli Lit possono accettare altri modelli Lit, noti come TemplateResult
. Ad esempio, aggrega name
in tag in corsivo (<i>
) e racchiudilo in un valore letterale di modello taggato N.B..Assicurati di utilizzare l'accento grave (`
) e non le virgolette singole ('
).
import {html, render} from 'lit';
const name = html`<i>Josh Perez</i>`;
const element = html`
<h1>Hello, ${name}</h1>
<div>How are you?</div>`;
render(
element,
mountNode
);
I TemplateResult
di Lit possono accettare array, stringhe, altri TemplateResult
e direttive.
Come esercizio, prova a convertire il seguente codice React in Lit:
const itemsToBuy = [
<li>Bananas</li>,
<li>oranges</li>,
<li>apples</li>,
<li>grapes</li>
];
const element = (
<>
<h1>Things to buy:</h1>
<ol>
{itemsToBuy}
</ol>
</>);
ReactDOM.render(
element,
mountNode
);
Risposta:
import {html, render} from 'lit';
const itemsToBuy = [
html`<li>Bananas</li>`,
html`<li>oranges</li>`,
html`<li>apples</li>`,
html`<li>grapes</li>`
];
const element = html`
<h1>Things to buy:</h1>
<ol>
${itemsToBuy}
</ol>`;
render(
element,
mountNode
);
Passare e impostare oggetti
Una delle principali differenze tra le sintassi di JSX e di Lit è la sintassi dell'associazione di dati. Ad esempio, prendiamo questo input React con le associazioni:
const disabled = false;
const label = 'my label';
const myClass = 'my-class';
const value = 'my value';
const element =
<input
disabled={disabled}
className={`static-class ${myClass}`}
defaultValue={value}/>;
ReactDOM.render(
element,
mountNode
);
Nell'esempio precedente, viene definito un input che fa quanto segue:
- Imposta il valore disabilitato su una variabile definita (in questo caso false)
- Imposta la classe su
static-class
più una variabile (in questo caso"static-class my-class"
) - Imposta un valore predefinito
In Lit, svolgi i seguenti passaggi:
import {html, render} from 'lit';
const disabled = false;
const label = 'my label';
const myClass = 'my-class';
const value = 'my value';
const element = html`
<input
?disabled=${disabled}
class="static-class ${myClass}"
.value=${value}>`;
render(
element,
mountNode
);
Nell'esempio di Lit, viene aggiunta un'associazione booleana per attivare/disattivare l'attributo disabled
.
Successivamente, è presente una associazione diretta all'attributo class
anziché a className
. È possibile aggiungere più associazioni all'attributo class
, a meno che non utilizzi la direttiva classMap
, che è un'utilità dichiarativa per attivare/disattivare le classi.
Infine, la proprietà value
viene impostata sull'input. A differenza di React, l'elemento di input non verrà impostato come di sola lettura perché segue l'implementazione e il comportamento nativo dell'input.
Sintassi di associazione delle istanze Lit
html`<my-element ?attribute-name=${booleanVar}>`;
- Il prefisso
?
è la sintassi di associazione per attivare/disattivare un attributo in un elemento - Equivalente a
inputRef.toggleAttribute('attribute-name', booleanVar)
- Utile per gli elementi che utilizzano
disabled
perchédisabled="false"
viene ancora letto come vero dal DOM perchéinputElement.hasAttribute('disabled') === true
html`<my-element .property-name=${anyVar}>`;
- Il prefisso
.
è la sintassi di associazione per l'impostazione di una proprietà di un elemento - Equivalente a
inputRef.propertyName = anyVar
- Ideale per il trasferimento di dati complessi come oggetti, array o classi
html`<my-element attribute-name=${stringVar}>`;
- Si lega all'attributo di un elemento
- Equivalente a
inputRef.setAttribute('attribute-name', stringVar)
- Ottimo per valori di base, selettori di regole di stile e querySelector
Gestori del passaggio
const disabled = false;
const label = 'my label';
const myClass = 'my-class';
const value = 'my value';
const element =
<input
onClick={() => console.log('click')}
onChange={e => console.log(e.target.value)} />;
ReactDOM.render(
element,
mountNode
);
Nell'esempio riportato sopra, è definito un input che esegue le seguenti operazioni:
- Registra la parola "click" quando viene fatto clic sull'input
- Registra il valore dell'input quando l'utente digita un carattere
In Lit, svolgi i seguenti passaggi:
import {html, render} from 'lit';
const disabled = false;
const label = 'my label';
const myClass = 'my-class';
const value = 'my value';
const element = html`
<input
@click=${() => console.log('click')}
@input=${e => console.log(e.target.value)}>`;
render(
element,
mountNode
);
Nell'esempio Lit, è stato aggiunto un listener all'evento click
con @click
.
Poi, invece di utilizzare onChange
, è presente un'associazione all'evento input
nativo di <input>
poiché questo change
evento nativo viene attivato solo su blur
(reagisci a questi eventi).
Sintassi del gestore di eventi Lit
html`<my-element @event-name=${() => {...}}></my-element>`;
- Il prefisso
@
è la sintassi di binding per un gestore di eventi - Equivalente a
inputRef.addEventListener('event-name', ...)
- Utilizza nomi di eventi DOM nativi
5. Componenti e oggetti di scena
In questa sezione scoprirai i componenti e le funzioni della classe Lit. Stato e hook sono trattati in modo più dettagliato nelle sezioni successive.
Componenti della classe e LitElement
L'equivalente di Lit di un componente di classe React è LitElement e il concetto di "proprietà reattive" di Lit è una combinazione di prop e stato di React. Ad esempio:
import React from 'react';
import ReactDOM from 'react-dom';
class Welcome extends React.Component {
constructor(props) {
super(props);
this.state = {name: ''};
}
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
const element = <Welcome name="Elliott"/>
ReactDOM.render(
element,
mountNode
);
Nell'esempio precedente è presente un componente React che:
- Visualizza un
name
- Imposta il valore predefinito di
name
sulla stringa vuota (""
) - Riassegna
name
a"Elliott"
Ecco come fare in LitElement
In TypeScript:
import {LitElement, html} from 'lit';
import {customElement, property} from 'lit/decorators.js';
@customElement('welcome-banner')
class WelcomeBanner extends LitElement {
@property({type: String})
name = '';
render() {
return html`<h1>Hello, ${this.name}</h1>`
}
}
In JavaScript:
import {LitElement, html} from 'lit';
class WelcomeBanner extends LitElement {
static get properties() {
return {
name: {type: String}
}
}
constructor() {
super();
this.name = '';
}
render() {
return html`<h1>Hello, ${this.name}</h1>`
}
}
customElements.define('welcome-banner', WelcomeBanner);
Nel file HTML:
<!-- index.html -->
<head>
<script type="module" src="./index.js"></script>
</head>
<body>
<welcome-banner name="Elliott"></welcome-banner>
</body>
Un riepilogo di ciò che accade nell'esempio riportato sopra:
@property({type: String})
name = '';
- Definisce una proprietà reattiva pubblica, una parte dell'API pubblica del componente
- Espone un attributo (per impostazione predefinita) e una proprietà nel componente
- Definisce come tradurre l'attributo del componente (che sono stringhe) in un valore
static get properties() {
return {
name: {type: String}
}
}
- Ha la stessa funzione del decorator TS
@property
, ma viene eseguita in modo nativo in JavaScript
render() {
return html`<h1>Hello, ${this.name}</h1>`
}
- Questo viene richiamato ogni volta che viene modificata una proprietà reattiva
@customElement('welcome-banner')
class WelcomeBanner extends LitElement {
...
}
- Ciò associa il nome di un tag Elemento HTML a una definizione di classe
- A causa dello standard Elementi personalizzati, il nome del tag deve includere un trattino (-)
this
in un LitElement si riferisce all'istanza dell'elemento personalizzato (in questo caso<welcome-banner>
)
customElements.define('welcome-banner', WelcomeBanner);
- Questo è l'equivalente in JavaScript del decoratore TS
@customElement
<head>
<script type="module" src="./index.js"></script>
</head>
- Importa la definizione dell'elemento personalizzato
<body>
<welcome-banner name="Elliott"></welcome-banner>
</body>
- Aggiunge l'elemento personalizzato alla pagina
- Imposta la proprietà
name
su'Elliott'
Componenti delle funzioni
Lit non ha un'interpretazione 1:1 di un componente funzione perché non utilizza JSX o un preprocessore. Tuttavia, è abbastanza semplice comporre una funzione che prende le proprietà ed esegue il rendering del DOM in base a queste proprietà. Ad esempio:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
const element = <Welcome name="Elliott"/>
ReactDOM.render(
element,
mountNode
);
In Lit, sarà:
import {html, render} from 'lit';
function Welcome(props) {
return html`<h1>Hello, ${props.name}</h1>`;
}
render(
Welcome({name: 'Elliott'}),
document.body.querySelector('#root')
);
6. Stato e ciclo di vita
In questa sezione imparerai a conoscere lo stato e il ciclo di vita di Lit.
Stato
Il concetto di "Proprietà reattive" di Lit è un mix di stato e oggetti di React. Se modificate, le proprietà reattive possono attivare il ciclo di vita del componente. Le proprietà reattive sono disponibili in due varianti:
Proprietà reattive pubbliche
// React
import React from 'react';
class MyEl extends React.Component {
constructor(props) {
super(props)
this.state = {name: 'there'}
}
componentWillReceiveProps(nextProps) {
if (this.props.name !== nextProps.name) {
this.setState({name: nextProps.name})
}
}
}
// Lit (TS)
import {LitElement} from 'lit';
import {property} from 'lit/decorators.js';
class MyEl extends LitElement {
@property() name = 'there';
}
- Definito da
@property
- Simile a props e state di React, ma mutabile
- API pubblica accessibile e impostata dai consumer del componente
Stato reattivo interno
// React
import React from 'react';
class MyEl extends React.Component {
constructor(props) {
super(props)
this.state = {name: 'there'}
}
}
// Lit (TS)
import {LitElement} from 'lit';
import {state} from 'lit/decorators.js';
class MyEl extends LitElement {
@state() name = 'there';
}
- Definito da
@state
- Simile allo stato di React, ma modificabile
- Stato interno privato a cui si accede in genere dall'interno del componente o delle sottoclassi
Lifecycle
Il ciclo di vita di Lit è abbastanza simile a quello di React, ma ci sono alcune differenze significative.
constructor
// React (js)
import React from 'react';
class MyEl extends React.Component {
constructor(props) {
super(props);
this.state = { counter: 0 };
this._privateProp = 'private';
}
}
// Lit (ts)
class MyEl extends LitElement {
@property({type: Number}) counter = 0;
private _privateProp = 'private';
}
// Lit (js)
class MyEl extends LitElement {
static get properties() {
return { counter: {type: Number} }
}
constructor() {
this.counter = 0;
this._privateProp = 'private';
}
}
- L'equivalente in litri è anche
constructor
- Non è necessario passare nulla alla videochiamata
- Richiamato da (non completamente inclusivo):
document.createElement
document.innerHTML
new ComponentClass()
- Se nella pagina è presente un nome di tag non aggiornato e la definizione viene caricata e registrata con
@customElement
ocustomElements.define
- Funzione simile a
constructor
della reazione
render
// React
render() {
return <div>Hello World</div>
}
// Lit
render() {
return html`<div>Hello World</div>`;
}
- L'equivalente Lit è anche
render
- Può restituire qualsiasi risultato di cui è possibile eseguire il rendering, ad esempio
TemplateResult
ostring
e così via. - Come in React,
render()
deve essere una funzione pura - Verrà visualizzato nel nodo restituito da
createRenderRoot()
(ShadowRoot
per impostazione predefinita)
componentDidMount
componentDidMount
è simile a una combinazione dei callback del ciclo di vita firstUpdated
e connectedCallback
di Lit.
firstUpdated
import Chart from 'chart.js';
// React
componentDidMount() {
this._chart = new Chart(this.chartElRef.current, {...});
}
// Lit
firstUpdated() {
this._chart = new Chart(this.chartEl, {...});
}
- Richiamato la prima volta che il modello del componente viene visualizzato nella directory principale del componente
- Verrà chiamato solo se l'elemento è collegato, ad esempio non viene chiamato tramite
document.createElement('my-component')
finché il nodo non viene aggiunto all'albero DOM - È un ottimo posto per eseguire la configurazione di un componente che richiede il rendering del DOM
- A differenza di
componentDidMount
di React, le modifiche alle proprietà reattive infirstUpdated
causeranno un nuovo rendering, anche se in genere il browser raggruppa le modifiche nello stesso frame. Se queste modifiche non richiedono l'accesso al DOM della directory principale, in genere dovrebbero essere inserite inwillUpdate
connectedCallback
// React
componentDidMount() {
this.window.addEventListener('resize', this.boundOnResize);
}
// Lit
connectedCallback() {
super.connectedCallback();
this.window.addEventListener('resize', this.boundOnResize);
}
- Richiamato ogni volta che l'elemento personalizzato viene inserito nell'albero DOM
- A differenza dei componenti React, quando gli elementi personalizzati vengono scollegati dal DOM non vengono eliminati e quindi possono essere "collegati" più volte
firstUpdated
non verrà più richiamato
- Utile per reinizializzare il DOM o ricollegare gli ascoltatori di eventi che sono stati ripuliti al momento della disconnessione
- Nota:
connectedCallback
potrebbe essere chiamato prima del giornofirstUpdated
, quindi alla prima chiamata il DOM potrebbe non essere disponibile
componentDidUpdate
// React
componentDidUpdate(prevProps) {
if (this.props.title !== prevProps.title) {
this._chart.setTitle(this.props.title);
}
}
// Lit (ts)
updated(prevProps: PropertyValues<this>) {
if (prevProps.has('title')) {
this._chart.setTitle(this.title);
}
}
- L'equivalente in lit è
updated
(utilizzando il tempo passato inglese di "update") - A differenza di React,
updated
viene chiamato anche al rendering iniziale - Funzione simile a
componentDidUpdate
della reazione
componentWillUnmount
// React
componentWillUnmount() {
this.window.removeEventListener('resize', this.boundOnResize);
}
// Lit
disconnectedCallback() {
super.disconnectedCallback();
this.window.removeEventListener('resize', this.boundOnResize);
}
- L'equivalente in litri è simile a
disconnectedCallback
- A differenza dei componenti React, quando gli elementi personalizzati vengono scollegati dal DOM, il componente non viene distrutto
- A differenza di
componentWillUnmount
,disconnectedCallback
viene chiamato dopo che l'elemento è stato rimosso dall'albero - Il DOM all'interno della radice è ancora collegato al sottoalbero della radice
- Utile per ripulire gli ascoltatori di eventi e i riferimenti con perdite in modo che il browser possa eseguire la raccolta dei rifiuti del componente
Esercizio
import React from 'react';
import ReactDOM from 'react-dom';
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
Nell'esempio precedente, esiste un orologio semplice che esegue queste operazioni:
- Viene visualizzato "Hello World! È" e poi mostra l'ora
- Aggiorna l'orologio ogni secondo
- Quando viene smontato, viene cancellato l'intervallo che chiama il tick
Inizia con la dichiarazione della classe del componente:
// Lit (TS)
// some imports here are imported in advance
import {LitElement, html} from 'lit';
import {customElement, state} from 'lit/decorators.js';
@customElement('lit-clock')
class LitClock extends LitElement {
}
// Lit (JS)
// `html` is imported in advance
import {LitElement, html} from 'lit';
class LitClock extends LitElement {
}
customElements.define('lit-clock', LitClock);
Poi, inizializza date
e dichiarala una proprietà reattiva interna con @state
, poiché gli utenti del componente non imposteranno date
direttamente.
// Lit (TS)
import {LitElement, html} from 'lit';
import {customElement, state} from 'lit/decorators.js';
@customElement('lit-clock')
class LitClock extends LitElement {
@state() // declares internal reactive prop
private date = new Date(); // initialization
}
// Lit (JS)
import {LitElement, html} from 'lit';
class LitClock extends LitElement {
static get properties() {
return {
// declares internal reactive prop
date: {state: true}
}
}
constructor() {
super();
// initialization
this.date = new Date();
}
}
customElements.define('lit-clock', LitClock);
Poi, esegui il rendering del modello.
// Lit (JS & TS)
render() {
return html`
<div>
<h1>Hello, World!</h1>
<h2>It is ${this.date.toLocaleTimeString()}.</h2>
</div>
`;
}
Ora implementa il metodo tick.
tick() {
this.date = new Date();
}
Poi viene l'implementazione di componentDidMount
. Anche in questo caso, l'analogo Lit è una combinazione di firstUpdated
e connectedCallback
. Nel caso di questo componente, l'utilizzo di tick
con setInterval
non richiede l'accesso al DOM all'interno dell'elemento principale. Inoltre, l'intervallo viene cancellato quando l'elemento viene rimosso dall'albero del documento, quindi se viene ricollegato, l'intervallo deve essere riavviato. Pertanto, connectedCallback
è una scelta migliore in questo caso.
// Lit (TS)
@customElement('lit-clock')
class LitClock extends LitElement {
@state()
private date = new Date();
// initialize timerId for TS
private timerId = -1 as unknown as ReturnType<typeof setTimeout>;
connectedCallback() {
super.connectedCallback();
this.timerId = setInterval(
() => this.tick(),
1000
);
}
...
}
// Lit (JS)
constructor() {
super();
// initialization
this.date = new Date();
this.timerId = -1; // initialize timerId for JS
}
connectedCallback() {
super.connectedCallback();
this.timerId = setInterval(
() => this.tick(),
1000
);
}
Infine, ripulisci l'intervallo in modo che non esegua il tick dopo che l'elemento è stato scollegato dall'albero del documento.
// Lit (TS & JS)
disconnectedCallback() {
super.disconnectedCallback();
clearInterval(this.timerId);
}
Riassumendo, il risultato dovrebbe essere simile a questo:
// Lit (TS)
import {LitElement, html} from 'lit';
import {customElement, state} from 'lit/decorators.js';
@customElement('lit-clock')
class LitClock extends LitElement {
@state()
private date = new Date();
private timerId = -1 as unknown as ReturnType<typeof setTimeout>;
connectedCallback() {
super.connectedCallback();
this.timerId = setInterval(
() => this.tick(),
1000
);
}
tick() {
this.date = new Date();
}
render() {
return html`
<div>
<h1>Hello, World!</h1>
<h2>It is ${this.date.toLocaleTimeString()}.</h2>
</div>
`;
}
disconnectedCallback() {
super.disconnectedCallback();
clearInterval(this.timerId);
}
}
// Lit (JS)
import {LitElement, html} from 'lit';
class LitClock extends LitElement {
static get properties() {
return {
date: {state: true}
}
}
constructor() {
super();
this.date = new Date();
}
connectedCallback() {
super.connectedCallback();
this.timerId = setInterval(
() => this.tick(),
1000
);
}
tick() {
this.date = new Date();
}
render() {
return html`
<div>
<h1>Hello, World!</h1>
<h2>It is ${this.date.toLocaleTimeString()}.</h2>
</div>
`;
}
disconnectedCallback() {
super.disconnectedCallback();
clearInterval(this.timerId);
}
}
customElements.define('lit-clock', LitClock);
7. Hooks
In questa sezione imparerai a tradurre i concetti di hook di React in Lit.
Concetti degli hook di React
Gli hook di reazione consentono di "agganciare" i componenti della funzione allo stato. Questo approccio offre diversi vantaggi.
- Semplificano il riutilizzo della logica stateful
- Aiuta a suddividere un componente in funzioni più piccole
Inoltre, l'attenzione ai componenti basati su funzioni ha risolto alcuni problemi relativi alla sintassi basata su classi di React, ad esempio:
- Passaggio
props
daconstructor
asuper
- L'inizializzazione disordinata delle proprietà in
constructor
- Questo era un motivo dichiarato dal team di React all'epoca, ma risolto da ES2019
- Problemi causati dal fatto che
this
non fa più riferimento al componente
Concetti di hook di React in Lit
Come menzionato nella sezione Componenti e oggetti, Lit non offre un modo per creare elementi personalizzati da una funzione, ma LitElement risolve la maggior parte dei problemi principali relativi ai componenti delle classi React. Ad esempio:
// React (at the time of making hooks)
import React from 'react';
import ReactDOM from 'react-dom';
class MyEl extends React.Component {
constructor(props) {
super(props); // Leaky implementation
this.state = {count: 0};
this._chart = null; // Deemed messy
}
render() {
return (
<>
<div>Num times clicked {count}</div>
<button onClick={this.clickCallback}>click me</button>
</>
);
}
clickCallback() {
// Errors because `this` no longer refers to the component
this.setState({count: this.count + 1});
}
}
// Lit (ts)
class MyEl extends LitElement {
@property({type: Number}) count = 0; // No need for constructor to set state
private _chart = null; // Public class fields introduced to JS in 2019
render() {
return html`
<div>Num times clicked ${count}</div>
<button @click=${this.clickCallback}>click me</button>`;
}
private clickCallback() {
// No error because `this` refers to component
this.count++;
}
}
In che modo Lit risolve questi problemi?
constructor
non accetta argomenti- Tutte e
@event
le associazioni vengono associate automaticamente athis
this
nella maggior parte dei casi si riferisce al riferimento dell'elemento personalizzato- Ora è possibile creare un'istanza per le proprietà delle classi come membri dei corsi. Esegue la pulizia delle implementazioni basate sul costruttore
Controller reattivi
I concetti principali alla base degli hook esistono in Lit come controller reattivi. I pattern di controller reattivi consentono la condivisione della logica stateful, la suddivisione dei componenti in bit più piccoli e più modulari e il collegamento al ciclo di vita di aggiornamento di un elemento.
Un controller reattivo è un'interfaccia oggetto che può essere collegata al ciclo di vita dell'aggiornamento di un host controller come LitElement.
Il ciclo di vita di un ReactiveController
e di un reactiveControllerHost
è il seguente:
interface ReactiveController {
hostConnected(): void;
hostUpdate(): void;
hostUpdated(): void;
hostDisconnected(): void;
}
interface ReactiveControllerHost {
addController(controller: ReactiveController): void;
removeController(controller: ReactiveController): void;
requestUpdate(): void;
readonly updateComplete: Promise<boolean>;
}
Se crei un controller reattivo e lo colleghi a un host con addController
, il ciclo di vita del controller verrà chiamato insieme a quello dell'host. Ad esempio, ricorda l'esempio dell'orologio nella sezione Stato e ciclo di vita:
import React from 'react';
import ReactDOM from 'react-dom';
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
Nell'esempio precedente, un orologio semplice esegue le seguenti operazioni:
- Viene visualizzato "Hello World! È" e poi mostra l'ora
- Aggiorna l'orologio ogni secondo
- Quando il dispositivo è smontato viene cancellato l'intervallo che chiama il segno di spunta.
Creazione dell'impalcatura del componente
Inizia con la dichiarazione della classe del componente e aggiungi la funzione render
.
// Lit (TS) - index.ts
import {LitElement, html} from 'lit';
import {customElement} from 'lit/decorators.js';
@customElement('my-element')
class MyElement extends LitElement {
render() {
return html`
<div>
<h1>Hello, world!</h1>
<h2>It is ${'time to get Lit'}.</h2>
</div>
`;
}
}
// Lit (JS) - index.js
import {LitElement, html} from 'lit';
class MyElement extends LitElement {
render() {
return html`
<div>
<h1>Hello, world!</h1>
<h2>It is ${'time to get Lit'}.</h2>
</div>
`;
}
}
customElements.define('my-element', MyElement);
Creazione del controller
Ora passa a clock.ts
, crea un corso per ClockController
e configura constructor
:
// Lit (TS) - clock.ts
import {ReactiveController, ReactiveControllerHost} from 'lit';
export class ClockController implements ReactiveController {
private readonly host: ReactiveControllerHost;
constructor(host: ReactiveControllerHost) {
this.host = host;
host.addController(this);
}
hostConnected() {
}
private tick() {
}
hostDisconnected() {
}
}
// Lit (JS) - clock.js
export class ClockController {
constructor(host) {
this.host = host;
host.addController(this);
}
hostConnected() {
}
tick() {
}
hostDisconnected() {
}
}
Un controller reattivo può essere creato in qualsiasi modo purché condivida l'interfaccia ReactiveController
, ma l'utilizzo di una classe con un constructor
che può accettare un'interfaccia ReactiveControllerHost
e qualsiasi altra proprietà necessaria per inizializzare il controller è un pattern che il team di Lit preferisce utilizzare per la maggior parte dei casi di base.
Ora devi tradurre i callback del ciclo di vita React in callback del controller. In breve:
componentDidMount
- A
connectedCallback
di LitElement - Al dispositivo
hostConnected
del controller
- A
ComponentWillUnmount
- A
disconnectedCallback
di LitElement - Al
hostDisconnected
del controller
- A
Per saperne di più sulla traduzione del ciclo di vita della reazione al ciclo di vita Lit, consulta la sezione Stato e ciclo di vita.
Successivamente, implementa il callback hostConnected
e i metodi tick
e pulisci l'intervallo in hostDisconnected
come mostrato nell'esempio nella sezione Stato e ciclo di vita.
// Lit (TS) - clock.ts
export class ClockController implements ReactiveController {
private readonly host: ReactiveControllerHost;
private interval = 0 as unknown as ReturnType<typeof setTimeout>;
date = new Date();
constructor(host: ReactiveControllerHost) {
this.host = host;
host.addController(this);
}
hostConnected() {
this.interval = setInterval(() => this.tick(), 1000);
}
private tick() {
this.date = new Date();
}
hostDisconnected() {
clearInterval(this.interval);
}
}
// Lit (JS) - clock.js
export class ClockController {
interval = 0;
host;
date = new Date();
constructor(host) {
this.host = host;
host.addController(this);
}
hostConnected() {
this.interval = setInterval(() => this.tick(), 1000);
}
tick() {
this.date = new Date();
}
hostDisconnected() {
clearInterval(this.interval);
}
}
Utilizzare il controller
Per utilizzare il controller dell'orologio, importa il controller e aggiorna il componente in index.ts
o index.js
.
// Lit (TS) - index.ts
import {LitElement, html, ReactiveController, ReactiveControllerHost} from 'lit';
import {customElement} from 'lit/decorators.js';
import {ClockController} from './clock.js';
@customElement('my-element')
class MyElement extends LitElement {
private readonly clock = new ClockController(this); // Instantiate
render() {
// Use controller
return html`
<div>
<h1>Hello, world!</h1>
<h2>It is ${this.clock.date.toLocaleTimeString()}.</h2>
</div>
`;
}
}
// Lit (JS) - index.js
import {LitElement, html} from 'lit';
import {ClockController} from './clock.js';
class MyElement extends LitElement {
clock = new ClockController(this); // Instantiate
render() {
// Use controller
return html`
<div>
<h1>Hello, world!</h1>
<h2>It is ${this.clock.date.toLocaleTimeString()}.</h2>
</div>
`;
}
}
customElements.define('my-element', MyElement);
Per utilizzare il controller, devi creare un'istanza del controller passando un riferimento all'host del controller (che è il componente <my-element>
), quindi utilizzare il controller nel metodo render
.
Attivazione di nuovi rendering nel controller
Tieni presente che verrà visualizzata l'ora, ma non viene aggiornata. Questo accade perché il controller imposta la data ogni secondo, ma l'host non si aggiorna. Questo perché date
sta cambiando nella classe ClockController
e non più nel componente. Ciò significa che dopo aver impostato date
sul controller, all'host deve essere chiesto di eseguire il ciclo di vita dell'aggiornamento con host.requestUpdate()
.
// Lit (TS & JS) - clock.ts / clock.js
private tick() {
this.date = new Date();
this.host.requestUpdate();
}
Ora il tempo dovrebbe far suonare!
Per un confronto più approfondito dei casi d'uso comuni con gli hook, consulta la sezione Argomenti avanzati - Hook.
8. Bambini
In questa sezione imparerai a utilizzare gli slot per gestire i figli in Lit.
Slot machine e bambini
Gli slot consentono la composizione consentendo di nidificare i componenti.
In React, i bambini vengono ereditati tramite gli oggetti di scena. L'area predefinita è props.children
e la funzione render
definisce la posizione dell'area predefinita. Ad esempio:
const MyArticle = (props) => {
return <article>{props.children}</article>;
};
Tieni presente che props.children
sono componenti di reazione e non elementi HTML.
In Lit, i bambini sono composti nella funzione di rendering con elementi slot. Tieni presente che gli elementi secondari non vengono ereditati nello stesso modo di React. In Lit, gli elementi secondari sono HTMLElements associati agli slot. Questo allegato è chiamato Proiezione.
@customElement("my-article")
export class MyArticle extends LitElement {
render() {
return html`
<article>
<slot></slot>
</article>
`;
}
}
Più slot
In React, l'aggiunta di più slot è essenzialmente equivalente all'eredità di più prop.
const MyArticle = (props) => {
return (
<article>
<header>
{props.headerChildren}
</header>
<section>
{props.sectionChildren}
</section>
</article>
);
};
Allo stesso modo, l'aggiunta di più elementi <slot>
crea più spazi in Lit. Sono definiti più slot con l'attributo name
: <slot name="slot-name">
. In questo modo, i bambini possono dichiarare a quale fascia oraria verrà assegnato il loro turno.
@customElement("my-article")
export class MyArticle extends LitElement {
render() {
return html`
<article>
<header>
<slot name="headerChildren"></slot>
</header>
<section>
<slot name="sectionChildren"></slot>
</section>
</article>
`;
}
}
Contenuti slot predefiniti
Gli slot mostreranno il sottoalbero quando non ci sono nodi previsti per quell'area. Quando vengono proiettati i nodi in uno slot, quest'ultimo non mostrerà il sottoalbero ma i nodi proiettati.
@customElement("my-element")
export class MyElement extends LitElement {
render() {
return html`
<section>
<div>
<slot name="slotWithDefault">
<p>
This message will not be rendered when children are attached to this slot!
<p>
</slot>
</div>
</section>
`;
}
}
Assegnare i bambini agli spazi
In React, gli elementi secondari vengono assegnati alle aree tramite le proprietà di un componente. Nell'esempio seguente, gli elementi React vengono passati ai prop headerChildren
e sectionChildren
.
const MyNewsArticle = () => {
return (
<MyArticle
headerChildren={<h3>Extry, Extry! Read all about it!</h3>}
sectionChildren={<p>Children are props in React!</p>}
/>
);
};
In Lit, i bambini vengono assegnati agli slot utilizzando l'attributo slot
.
@customElement("my-news-article")
export class MyNewsArticle extends LitElement {
render() {
return html`
<my-article>
<h3 slot="headerChildren">
Extry, Extry! Read all about it!
</h3>
<p slot="sectionChildren">
Children are composed with slots in Lit!
</p>
</my-article>
`;
}
}
Se non è presente uno slot predefinito (ad es. <slot>
) e non è presente uno slot con un attributo name
(ad es. <slot name="foo">
) che corrisponda all'attributo slot
degli elementi secondari dell'elemento personalizzato (ad es. <div slot="foo">
), il nodo non verrà proiettato e non verrà visualizzato.
9. Riferimenti
A volte, uno sviluppatore potrebbe dover accedere all'API di un HTMLElement.
In questa sezione scoprirai come acquisire i riferimenti agli elementi in Lit.
Riferimenti a React
Un componente React viene trasferito in una serie di chiamate di funzione che creano un DOM virtuale quando viene richiamato. Questo DOM virtuale viene interpretato da ReactDOM e visualizza gli elementi HTMLElement.
In React, i Refs sono uno spazio in memoria per contenere un HTMLElement generato.
const RefsExample = (props) => {
const inputRef = React.useRef(null);
const onButtonClick = React.useCallback(() => {
inputRef.current?.focus();
}, [inputRef]);
return (
<div>
<input type={"text"} ref={inputRef} />
<br />
<button onClick={onButtonClick}>
Click to focus on the input above!
</button>
</div>
);
};
Nell'esempio precedente, il componente React:
- Esegui il rendering di un'input di testo vuoto e di un pulsante con testo
- Mettere in primo piano l'input quando si fa clic sul pulsante
Dopo il rendering iniziale, React imposterà inputRef.current
sul valore HTMLInputElement
generato tramite l'attributo ref
.
"Riferimenti" illuminato con @query
Lit è integrato nel browser e crea un'astrazione molto sottile sulle funzionalità native del browser.
La reazione equivalente a refs
in Lit è l'elemento HTMLElement restituito dai decoratori @query
e @queryAll
.
@customElement("my-element")
export class MyElement extends LitElement {
@query('input') // Define the query
inputEl!: HTMLInputElement; // Declare the prop
// Declare the click event listener
onButtonClick() {
// Use the query to focus
this.inputEl.focus();
}
render() {
return html`
<input type="text">
<br />
<!-- Bind the click listener -->
<button @click=${this.onButtonClick}>
Click to focus on the input above!
</button>
`;
}
}
Nell'esempio precedente, il componente Lit esegue le seguenti operazioni:
- Definisce una proprietà su
MyElement
utilizzando il decorator@query
(creazione di un getter per unHTMLInputElement
). - Dichiara e allega un callback dell'evento di clic denominato
onButtonClick
. - Imposta lo stato attivo sull'input al clic del pulsante
In JavaScript, i decorator @query
e @queryAll
eseguono rispettivamente querySelector
e querySelectorAll
. È l'equivalente JavaScript di @query('input') inputEl!: HTMLInputElement;
get inputEl() {
return this.renderRoot.querySelector('input');
}
Dopo che il componente Lit esegue il commit del modello del metodo render
nella radice di my-element
, il decorator @query
consentirà a inputEl
di restituire il primo elemento input
trovato nella radice di rendering. Restituisce null
se @query
non riesce a trovare l'elemento specificato.
Se ci fossero più elementi input
nella radice di rendering, @queryAll
restituisce un elenco di nodi.
10. Stato della mediazione
In questa sezione imparerai come mediare lo stato tra i componenti in Lit.
Componenti riutilizzabili
React imita le pipeline di rendering funzionali con flusso di dati dall'alto verso il basso. I componenti principali forniscono lo stato ai componenti secondari tramite gli elementi di scena. I bambini comunicano con i genitori tramite i callback trovati negli elementi di scena.
const CounterButton = (props) => {
const label = props.step < 0
? `- ${-1 * props.step}`
: `+ ${props.step}`;
return (
<button
onClick={() =>
props.addToCounter(props.step)}>{label}</button>
);
};
Nell'esempio riportato sopra, un componente React esegue le seguenti operazioni:
- Crea un'etichetta basata sul valore
props.step
. - Visualizza un pulsante con l'etichetta +step o -step
- Aggiorna il componente principale chiamando
props.addToCounter
conprops.step
come argomento al clic
Sebbene sia possibile passare i callback in Lit, i pattern convenzionali sono diversi. Il componente React nell'esempio precedente potrebbe essere scritto come componente illuminato nell'esempio seguente:
@customElement('counter-button')
export class CounterButton extends LitElement {
@property({type: Number}) step: number = 0;
onClick() {
const event = new CustomEvent('update-counter', {
bubbles: true,
detail: {
step: this.step,
}
});
this.dispatchEvent(event);
}
render() {
const label = this.step < 0
? `- ${-1 * this.step}` // "- 1"
: `+ ${this.step}`; // "+ 1"
return html`
<button @click=${this.onClick}>${label}</button>
`;
}
}
Nell'esempio precedente, un componente illuminato esegue le seguenti operazioni:
- Crea la proprietà reattiva
step
- Invia un evento personalizzato denominato
update-counter
che porta il valorestep
dell'elemento al clic
Gli eventi del browser vengono visualizzati dagli elementi secondari agli elementi principali. Gli eventi consentono ai bambini di trasmettere eventi di interazione e modifiche dello stato. Reagisce fondamentalmente passa lo stato nella direzione opposta, quindi è raro vedere i componenti React inviare e ascoltare gli eventi nello stesso modo dei componenti illuminati.
Componenti stateful
In React, è comune utilizzare gli hook per gestire lo stato. Un componente MyCounter
può essere creato riutilizzando il componente CounterButton
. Nota come addToCounter
viene passato a entrambe le istanze di CounterButton
.
const MyCounter = (props) => {
const [counterSum, setCounterSum] = React.useState(0);
const addToCounter = useCallback(
(step) => {
setCounterSum(counterSum + step);
},
[counterSum, setCounterSum]
);
return (
<div>
<h3>Σ: {counterSum}</h3>
<CounterButton
step={-1}
addToCounter={addToCounter} />
<CounterButton
step={1}
addToCounter={addToCounter} />
</div>
);
};
Nell'esempio precedente:
- Crea uno stato
count
. - Crea un callback che aggiunge un numero a uno stato
count
. CounterButton
utilizzaaddToCounter
per aggiornarecount
distep
a ogni clic.
È possibile ottenere un'implementazione simile di MyCounter
in Lit. Tieni presente che addToCounter
non viene passato a counter-button
. Il callback è invece associato come listener di eventi all'evento @update-counter
in un elemento principale.
@customElement("my-counter")
export class MyCounter extends LitElement {
@property({type: Number}) count = 0;
addToCounter(e: CustomEvent<{step: number}>) {
// Get step from detail of event or via @query
this.count += e.detail.step;
}
render() {
return html`
<div @update-counter="${this.addToCounter}">
<h3>Σ ${this.count}</h3>
<counter-button step="-1"></counter-button>
<counter-button step="1"></counter-button>
</div>
`;
}
}
L'esempio riportato sopra esegue le seguenti operazioni:
- Crea una proprietà reattiva denominata
count
che aggiorna il componente quando il valore viene modificato - Collega il callback
addToCounter
al listener di eventi@update-counter
- Aggiorna
count
aggiungendo il valore trovato nella sezionedetail.step
dell'eventoupdate-counter
- Imposta il valore
step
dicounter-button
tramite l'attributostep
È più convenzionale utilizzare proprietà reattive in Lit per trasmettere i cambiamenti da genitori a figli. Analogamente, è buona prassi utilizzare il sistema di eventi del browser per visualizzare i dettagli dal basso verso l'alto.
Questo approccio segue le best practice e rispetta lo scopo di Lit di fornire supporto multipiattaforma per i componenti web.
11. Stili
In questa sezione scoprirai come applicare uno stile in
Stili
Lit offre diversi modi per applicare uno stile agli elementi, oltre a una soluzione integrata.
Stili in linea
Lit supporta gli stili in linea e la loro associazione.
import {LitElement, html, css} from 'lit';
import {customElement} from 'lit/decorators.js';
@customElement('my-element')
class MyElement extends LitElement {
render() {
return html`
<div>
<h1 style="color:orange;">This text is orange</h1>
<h1 style="color:rebeccapurple;">This text is rebeccapurple</h1>
</div>
`;
}
}
Nell'esempio riportato sopra sono presenti due intestazioni, ciascuna con uno stile in linea.
Ora importa e vincola un bordo da border-color.js
al testo arancione:
...
import borderColor from './border-color.js';
...
html`
...
<h1 style="color:orange;${borderColor}">This text is orange</h1>
...`
Dover calcolare la stringa di stile ogni volta può essere un po' fastidioso, quindi Lit offre un'istruzione per risolvere questo problema.
styleMap
La direttiva styleMap
semplifica l'utilizzo di JavaScript per impostare gli stili in linea. Ad esempio:
import {LitElement, html, css} from 'lit';
import {customElement, property} from 'lit/decorators.js';
import {styleMap} from 'lit/directives/style-map.js';
@customElement('my-element')
class MyElement extends LitElement {
@property({type: String})
color = '#000'
render() {
// Define the styleMap
const headerStyle = styleMap({
'border-color': this.color,
});
return html`
<div>
<h1
style="border-style:solid;
<!-- Use the styleMap -->
border-width:2px;${headerStyle}">
This div has a border color of ${this.color}
</h1>
<input
type="color"
@input=${e => (this.color = e.target.value)}
value="#000">
</div>
`;
}
}
L'esempio riportato sopra esegue le seguenti operazioni:
- Viene visualizzato un
h1
con un bordo e un selettore di colori - Modifica
border-color
in base al valore del selettore di colori
Inoltre, è presente styleMap
, che viene utilizzato per impostare gli stili di h1
. styleMap
segue una sintassi simile alla sintassi di associazione degli attributi style
di React.
CSSResult
Il modo consigliato per applicare uno stile ai componenti è utilizzare il valore letterale del modello con tag css
.
import {LitElement, html, css} from 'lit';
import {customElement} from 'lit/decorators.js';
const ORANGE = css`orange`;
@customElement('my-element')
class MyElement extends LitElement {
static styles = [
css`
#orange {
color: ${ORANGE};
}
#purple {
color: rebeccapurple;
}
`
];
render() {
return html`
<div>
<h1 id="orange">This text is orange</h1>
<h1 id="purple">This text is rebeccapurple</h1>
</div>
`;
}
}
L'esempio sopra fa quanto segue:
- Dichiara un valore letterale di modello con tag CSS con un'associazione
- Imposta i colori di due
h1
con ID
Vantaggi dell'utilizzo del tag modello css
:
- Analizzati una volta per classe o per istanza
- Implementata tenendo presente la possibilità di riutilizzare i moduli
- Può separare facilmente gli stili all'interno dei propri file
- Compatibile con il polyfill delle proprietà personalizzate CSS
Inoltre, prendi nota del tag <style>
in index.html
:
<!-- index.html -->
<style>
h1 {
color: red !important;
}
</style>
Lit estende l'ambito degli stili dei componenti alle relative origini. Ciò significa che gli stili non si diffonderanno e non cadranno. Per trasferire gli stili ai componenti, il team di Lit consiglia di utilizzare le proprietà personalizzate CSS in quanto possono penetrare l'ambito degli stili Lit.
Tag di stile
È anche possibile semplicemente incorporare i tag <style>
nei modelli. Il browser deduplica questi tag di stile, ma, posizionandoli nei modelli, verranno analizzati per istanza del componente e non per classe, come nel caso del modello con tag css
. Inoltre, la deduplicazione del browser di CSSResult
è molto più veloce.
Tag link
Anche l'utilizzo di un elemento <link rel="stylesheet">
nel modello è una possibilità per gli stili, ma è sconsigliato poiché potrebbe causare un flash iniziale di contenuti senza stile (FOUC).
12. Argomenti avanzati (facoltativo)
JSX e modelli
DOM di Lit e virtuale
Lit-html non include un DOM virtuale convenzionale che differenzia ogni singolo nodo. Utilizza invece le funzionalità di prestazioni intrinseche alla specifica del letterale di modello con tag di ES2015. I letterali di modello con tag sono stringhe di letterali di modello con funzioni di tag associate.
Ecco un esempio di valore letterale di modello:
const str = 'string';
console.log(`This is a template literal ${str}`);
Ecco un esempio di un valore letterale di modello con tag:
const tag = (strings, ...values) => ({strings, values});
const f = (x) => tag`hello ${x} how are you`;
console.log(f('world')); // {strings: ["hello ", " how are you"], values: ["world"]}
console.log(f('world').strings === f(1 + 2).strings); // true
Nell'esempio precedente, il tag è la funzione tag
e la funzione f
restituisce una chiamata a un valore letterale di modello taggato.
Molte delle prestazioni straordinarie in Lit derivano dal fatto che gli array di stringhe passati nella funzione tag hanno lo stesso puntatore (come mostrato nel secondo console.log
). Il browser non ricrea un nuovo array strings
per ogni chiamata di funzione tag, perché utilizza lo stesso valore letterale modello (ovvero nella stessa posizione nell'AST). Quindi l'associazione, l'analisi e la memorizzazione nella cache dei modelli di Lit possono sfruttare queste caratteristiche senza un overhead per le differenze di runtime.
Questo comportamento del browser integrato dei literali di modello con tag offre a Lit un notevole vantaggio in termini di prestazioni. La maggior parte dei DOM virtuali convenzionali svolge la maggior parte del lavoro in JavaScript. Tuttavia, i valori letterali dei modelli con tag eseguono la maggior parte delle differenze nel C++ del browser.
Se vuoi iniziare a utilizzare le literali di template con tag HTML con React o Preact, il team di Lit consiglia la libreria htm
.
Tuttavia, come nel caso del sito Google Codelabs e di diversi editor di codice online, noterai che l'evidenziazione della sintassi dei literali di modello con tag non è molto comune. Alcuni IDE e editor di testo li supportano per impostazione predefinita, ad esempio Atom e lo strumento di evidenziazione del codice di GitHub. Inoltre, il team di Lit lavora a stretto contatto con la community per gestire progetti come lit-plugin
, un plug-in VS Code che aggiunge l'evidenziazione della sintassi, il controllo del tipo e l'intelligenza dei progetti Lit.
Lit e JSX + React DOM
JSX non viene eseguito nel browser e utilizza invece un preprocessore per convertire JSX in chiamate di funzione JavaScript (in genere tramite Babel).
Ad esempio, Babel trasformerà questo:
const element = <div className="title">Hello World!</div>;
ReactDOM.render(element, mountNode);
in questo modo:
const element = React.createElement('div', {className: 'title'}, 'Hello World!');
ReactDOM.render(element, mountNode);
React DOM prende quindi l'output React e lo converte nel DOM effettivo: proprietà, attributi, listener di eventi e tutto il resto.
Lit-html utilizza valori letterali di modelli con tag che possono essere eseguiti nel browser senza traspirazione o preprocessore. Ciò significa che per iniziare a utilizzare Lit, hai bisogno solo di un file HTML, uno script del modulo ES e un server. Ecco uno script completamente eseguibile dal browser:
<!DOCTYPE html>
<html>
<head>
<script type="module">
import {html, render} from 'https://cdn.skypack.dev/lit';
render(
html`<div>Hello World!</div>`,
document.querySelector('.root')
)
</script>
</head>
<body>
<div class="root"></div>
</body>
</html>
Inoltre, poiché il sistema di modelli di Lit, lit-html, non utilizza un DOM virtuale convenzionale ma utilizza direttamente l'API DOM, la dimensione di Lit 2 è inferiore a 5kb minimizzati e compressi rispetto a React (2,8kb) + 40kb minimizzati e compressi di reazione-dom (39,4kb) .
Eventi
React utilizza un sistema di eventi sintetici. Ciò significa che react-dom deve definire tutti gli eventi che verranno utilizzati in ogni componente e fornire un ascoltatore di eventi camelCase equivalente per ogni tipo di nodo. Di conseguenza, JSX non dispone di un metodo per definire un listener di eventi per un evento personalizzato e gli sviluppatori devono utilizzare un ref
e quindi applicare in modo imperativo un listener. Ciò crea un'esperienza utente non soddisfacente quando si integrano librerie che non sono progettate per React, con la conseguenza di dover scrivere un wrapper specifico per React.
Lit-html accede direttamente al DOM e utilizza eventi nativi, quindi aggiungere ascoltatori di eventi è semplicissimo. Ciò significa che viene effettuata una minore analisi del runtime per l'aggiunta di listener di eventi e di eventi di attivazione.
Componenti e accessori
Componenti React ed elementi personalizzati
Dietro le quinte, LitElement utilizza elementi personalizzati per pacchettizzare i suoi componenti. Gli elementi personalizzati introducono alcuni compromessi tra i componenti React in termini di componenti (stato e ciclo di vita sono illustrati più avanti nella sezione Stato e ciclo di vita).
Ecco alcuni vantaggi di Custom Elements come sistema di componenti:
- Nativi del browser e non richiedono strumenti
- Adattarsi a ogni API browser da
innerHTML
edocument.createElement
aquerySelector
- In genere possono essere utilizzati in più framework
- Può essere registrato in modo lazy con
customElements.define
e "hydrate" DOM
Alcuni svantaggi di Custom Elements rispetto ai componenti React:
- Non è possibile creare un elemento personalizzato senza definire una classe (quindi non sono ammessi componenti funzionali come JSX)
- Deve contenere un tag di chiusura
- Nota: nonostante la praticità per gli sviluppatori, i fornitori di browser tendono a non gradire la specifica dei tag autochiudenti, motivo per cui le specifiche più recenti tendono a non includerli.
- Introduce un nodo aggiuntivo nell'albero DOM che potrebbe causare problemi di layout
- Deve essere registrato tramite JavaScript
Lit ha adottato elementi personalizzati invece di un sistema di elementi su misura perché questi ultimi sono integrati nel browser. Il team di Lit ritiene che i vantaggi del cross-framework superino quelli offerti da un livello di astrazione dei componenti. Infatti, gli sforzi del team di Lit nello spazio lit-ssr hanno superato i problemi principali con la registrazione JavaScript. Inoltre, alcune aziende come GitHub sfruttano la registrazione lazy degli elementi personalizzati per migliorare progressivamente le pagine con elementi facoltativi.
Trasmissione di dati agli elementi personalizzati
Un equivoco comune con gli elementi personalizzati è che i dati possono essere trasmessi solo come stringhe. Questo malinteso probabilmente deriva dal fatto che gli attributi degli elementi possono essere scritti solo come stringhe. Sebbene sia vero che Lit eseguirà il casting degli attributi di stringa ai relativi tipi definiti, gli elementi personalizzati possono anche accettare dati complessi come proprietà.
Ad esempio, data la seguente definizione di LitElement:
// data-test.ts
import {LitElement, html} from 'lit';
import {customElement, property} from 'lit/decorators.js';
@customElement('data-test')
class DataTest extends LitElement {
@property({type: Number})
num = 0;
@property({attribute: false})
data = {a: 0, b: null, c: [html`<div>hello</div>`, html`<div>world</div>`]}
render() {
return html`
<div>num + 1 = ${this.num + 1}</div>
<div>data.a = ${this.data.a}</div>
<div>data.b = ${this.data.b}</div>
<div>data.c = ${this.data.c}</div>`;
}
}
Viene definita una proprietà reattiva primitiva num
che converte il valore di stringa di un attributo in un number
, quindi viene introdotta una struttura di dati complessa con attribute:false
che disattiva la gestione degli attributi di Lit.
Ecco come trasmettere dati a questo elemento personalizzato:
<head>
<script type="module">
import './data-test.js'; // loads element definition
import {html} from './data-test.js';
const el = document.querySelector('data-test');
el.data = {
a: 5,
b: null,
c: [html`<div>foo</div>`,html`<div>bar</div>`]
};
</script>
</head>
<body>
<data-test num="5"></data-test>
</body>
Stato e ciclo di vita
Altri callback del ciclo di vita di React
static getDerivedStateFromProps
Non esiste un equivalente in Lit perché props e state sono entrambe proprietà di classe
shouldComponentUpdate
- L'equivalente in litri è
shouldUpdate
- Viene chiamato al primo rendering, a differenza di React
- Funzione simile a
shouldComponentUpdate
di React
getSnapshotBeforeUpdate
In Lit, getSnapshotBeforeUpdate
è simile sia a update
che a willUpdate
willUpdate
- Chiamata effettuata prima del giorno
update
- A differenza di
getSnapshotBeforeUpdate
,willUpdate
viene chiamato prima dirender
- Le modifiche alle proprietà reattive in
willUpdate
non riattivano il ciclo di aggiornamento - Un buon punto per calcolare i valori delle proprietà che dipendono da altre proprietà e vengono utilizzati nel resto della procedura di aggiornamento
- Questo metodo viene chiamato sul server in SSR, quindi non è consigliabile accedere al DOM in questo caso
update
- Chiamata dopo il giorno
willUpdate
- A differenza di
getSnapshotBeforeUpdate
,update
viene chiamato prima dirender
- Le modifiche alle proprietà reattive in
update
non riattivano il ciclo di aggiornamento se vengono modificate prima di chiamaresuper.update
- Ottimo punto per acquisire informazioni dal DOM che circonda il componente prima che l'output visualizzato venga eseguito nel DOM
- Questo metodo non viene chiamato sul server in SSR
Altri callback del ciclo di vita di Lit
Esistono diversi callback del ciclo di vita che non sono stati menzionati nella sezione precedente perché non hanno un analogo in React. Sono:
attributeChangedCallback
Viene richiamato quando uno degli elementi observedAttributes
dell'elemento cambia. Sia observedAttributes
che attributeChangedCallback
fanno parte della specifica degli elementi personalizzati e sono implementati da Lit under the hood per fornire un'API degli attributi per gli elementi Lit.
adoptedCallback
Richiamato quando il componente viene spostato in un nuovo documento, ad esempio da documentFragment
di HTMLTemplateElement
all'elemento document
principale. Questo callback fa parte anche delle specifiche degli elementi personalizzati e deve essere utilizzato solo per casi d'uso avanzati quando il componente modifica i documenti.
Altri metodi e proprietà del ciclo di vita
Questi metodi e proprietà sono membri della classe che puoi chiamare, eseguire l'override o attendere per aiutare a manipolare il processo del ciclo di vita.
updateComplete
Si tratta di un Promise
che si risolve al termine dell'aggiornamento dell'elemento perché i cicli di vita di aggiornamento e rendering sono asincroni. Un esempio:
async nextButtonClicked() {
this.step++;
// Wait for the next "step" state to render
await this.updateComplete;
this.dispatchEvent(new Event('step-rendered'));
}
getUpdateComplete
Questo è un metodo che deve essere sostituito per personalizzare il momento in cui updateComplete
viene risolto. Questo accade spesso quando un componente esegue il rendering di un componente secondario e i relativi cicli di rendering devono essere sincronizzati. Ad esempio:
class MyElement extends LitElement {
...
async getUpdateComplete() {
await super.getUpdateComplete();
await this.myChild.updateComplete;
}
}
performUpdate
Questo metodo chiama i callback del ciclo di vita dell'aggiornamento. In genere non dovrebbe essere necessario, tranne in rari casi in cui l'aggiornamento deve essere eseguito in modo sincrono o per la pianificazione personalizzata.
hasUpdated
Questa proprietà è true
se il componente è stato aggiornato almeno una volta.
isConnected
Componente della specifica degli elementi personalizzati, questa proprietà sarà true
se l'elemento è attualmente collegato alla struttura ad albero del documento principale.
Visualizzazione del ciclo di vita dell'aggiornamento di Lit
Il ciclo di vita dell'aggiornamento è costituito da 3 parti:
- Prima dell'aggiornamento
- Aggiorna
- Post-aggiornamento
Pre-aggiornamento
Dopo il giorno requestUpdate
, è previsto un aggiornamento pianificato.
Aggiorna
Dopo l'aggiornamento
Hooks
Perché hook
Gli hook sono stati introdotti in React per casi d'uso di componenti di funzione semplici che richiedevano uno stato. In molti casi semplici, i componenti funzione con hook tendono ad essere molto più semplici e leggibili rispetto alle controparti dei componenti di classe. Tuttavia, quando vengono introdotti aggiornamenti dello stato asincroni e il passaggio di dati tra hook o effetti, il pattern hook tende a non essere sufficiente e una soluzione basata su classi come i controller reattivi tende a essere la scelta migliore.
Hook e controller di richieste API
È comune scrivere un hook che richiede dati da un'API. Ad esempio, prendi in considerazione questo componente della funzione React che esegue quanto segue:
index.tsx
- Visualizza il testo
- Viene visualizzata la risposta di
useAPI
- ID utente + nome utente
- Messaggio di errore
- 404 quando raggiunge l'utente 11 (come previsto)
- Errore di interruzione se il recupero dell'API viene interrotto
- Caricamento del messaggio
- Mostra un pulsante di azione
- Utente successivo: che recupera l'API per l'utente successivo
- Annulla: interrompe il recupero dell'API e mostra un errore
useApi.tsx
- Definisce un hook personalizzato
useApi
- Recupera in modo asincrono un oggetto utente da un'API
- Emissioni:
- Nome utente
- Indica se il recupero è in corso
- Eventuali messaggi di errore
- Un callback per interrompere il recupero
- Interrompi i recuperi in corso se smontato
- Definisce un hook personalizzato
Qui puoi trovare l'implementazione di Lit + Reactive Controller.
Concetti principali:
- I controller reattivi sono molto simili agli hook personalizzati
- Passaggio di dati non visualizzabili tra callback ed effetti
- La reazione utilizza
useRef
per trasmettere dati tra il giornouseEffect
e il giornouseCallback
- Lit utilizza una proprietà di una classe privata
- La reazione è essenzialmente una simulazione del comportamento di una proprietà di una classe privata
- La reazione utilizza
Inoltre, se ti piace molto la sintassi del componente funzione React con gli hook, ma vuoi lo stesso ambiente senza compilazione di Lit, il team di Lit consiglia vivamente la libreria Haunted.
Bambini
Slot predefinito
Quando agli elementi HTML non viene assegnato un attributo slot
, vengono assegnati allo slot senza nome predefinito. Nell'esempio seguente, MyApp
inserirà un paragrafo in un'area denominata. L'altro paragrafo verrà inserito per impostazione predefinita nello spazio senza nome".
@customElement("my-element")
export class MyElement extends LitElement {
render() {
return html`
<section>
<div>
<slot></slot>
</div>
<div>
<slot name="custom-slot"></slot>
</div>
</section>
`;
}
}
@customElement("my-app")
export class MyApp extends LitElement {
render() {
return html`
<my-element>
<p slot="custom-slot">
This paragraph will be placed in the custom-slot!
</p>
<p>
This paragraph will be placed in the unnamed default slot!
</p>
</my-element>
`;
}
}
Aggiornamenti slot
Quando la struttura dei discendenti delle aree annuncio cambia, viene attivato un evento slotchange
. Un componente Lit può associare un gestore eventi a un evento slotchange
. Nell'esempio seguente, i assignedNodes del primo slot trovato in shadowRoot
verranno registrati nella console il giorno slotchange
.
@customElement("my-element")
export class MyElement extends LitElement {
onSlotChange(e: Event) {
const slot = this.shadowRoot.querySelector('slot');
console.log(slot.assignedNodes({flatten: true}));
}
render() {
return html`
<section>
<div>
<slot @slotchange="{this.onSlotChange}"></slot>
</div>
</section>
`;
}
}
Riferimenti
Generazione di riferimenti
Sia Lit che React espongono un riferimento a un HTMLElement dopo l'esecuzione delle relative funzioni render
. Tuttavia, vale la pena esaminare come React e Lit compongono il DOM che viene successivamente restituito tramite un decoratore @query
di Lit o un riferimento React.
React è una pipeline funzionale che crea componenti React, non elementi HTMLElement. Poiché un Ref viene dichiarato prima che venga visualizzato un HTMLElement, viene allocato uno spazio in memoria. Questo è il motivo per cui viene visualizzato null
come valore iniziale di un riferimento, perché l'elemento DOM effettivo non è ancora stato creato (o visualizzato), ovvero useRef(null)
.
Dopo che ReactDOM ha convertito un componente React in un HTMLElement, cerca un attributo denominato ref
in ReactComponent. Se disponibile, ReactDOM inserisce il riferimento dell'elemento HTMLElement a ref.current
.
LitElement utilizza la html
funzione del tag template di lit-html per comporre un elemento modello sotto il cofano. LitElement stampa i contenuti del modello nello shadow DOM di un elemento personalizzato dopo il rendering. Lo shadow DOM è un albero DOM con ambito incapsulato da un elemento radice shadow. Il decorator @query
crea quindi un getter per la proprietà, che in sostanza esegue un this.shadowRoot.querySelector
sulla radice con ambito.
Query su più elementi
Nell'esempio riportato di seguito, il decorator @queryAll
restituirà i due paragrafi nella radice ombra come NodeList
.
@customElement("my-element")
export class MyElement extends LitElement {
@queryAll('p')
paragraphs!: NodeList;
render() {
return html`
<p>Hello, world!</p>
<p>How are you?</p>
`;
}
}
Essenzialmente, @queryAll
crea un getter per paragraphs
che restituisce i risultati di this.shadowRoot.querySelectorAll()
. In JavaScript, è possibile dichiarare che un getter ha lo stesso scopo:
get paragraphs() {
return this.renderRoot.querySelectorAll('p');
}
Elementi di modifica delle query
Il decoratore @queryAsync
è più adatto per gestire un nodo che può cambiare in base allo stato di un'altra proprietà dell'elemento.
Nell'esempio seguente, @queryAsync
troverà il primo elemento paragrafo. Tuttavia, un elemento paragrafo viene visualizzato solo quando renderParagraph
genera in modo casuale un numero dispari. L'istruzione @queryAsync
restituirà una promessa che verrà risolta quando sarà disponibile il primo paragrafo.
@customElement("my-dissappearing-paragraph")
export class MyDisapppearingParagraph extends LitElement {
@queryAsync('p')
paragraph!: Promise<HTMLElement>;
renderParagraph() {
const randomNumber = Math.floor(Math.random() * 10)
if (randomNumber % 2 === 0) {
return "";
}
return html`<p>This checkbox is checked!`
}
render() {
return html`
${this.renderParagraph()}
`;
}
}
Stato della mediazione
In React, la convenzione prevede l'uso dei callback perché lo stato è mediato dalla reazione stessa. Conviene non fare affidamento sullo stato fornito dagli elementi. Il DOM è semplicemente un effetto del processo di rendering.
Stato esterno
È possibile utilizzare Redux, MobX o qualsiasi altra libreria di gestione dello stato insieme a Lit.
I componenti Lit vengono creati nell'ambito del browser. Pertanto, qualsiasi libreria presente anche nell'ambito del browser è disponibile per Lit. Sono state costruite molte librerie straordinarie per utilizzare i sistemi di gestione degli stati esistenti in Lit.
Ecco una serie di Vaadin che spiega come utilizzare Redux in un componente Lit.
Dai un'occhiata a lit-mobx di Adobe per vedere come un sito su larga scala può sfruttare MobX in Lit.
Consulta anche Apollo Elements per vedere in che modo gli sviluppatori includono GraphQL nei loro componenti web.
Lit è compatibile con le funzionalità native del browser e la maggior parte delle soluzioni di gestione dello stato nell'ambito del browser può essere utilizzata in un componente Lit.
Stili
DOM shadow
Per incapsulare in modo nativo gli stili e il DOM all'interno di un elemento personalizzato, Lit utilizza Shadow DOM. Shadow Roots genera un albero di ombre separato dalla struttura ad albero dei documenti principale. Ciò significa che la maggior parte degli stili è limitata a questo documento. Si sono verificati alcuni stili, come il colore e altri stili relativi ai caratteri.
Shadow DOM introduce inoltre nuovi concetti e selettori nella specifica CSS:
:host, :host(:hover), :host([hover]) {
/* Styles the element in which the shadow root is attached to */
}
slot[name="title"]::slotted(*), slot::slotted(:hover), slot::slotted([hover]) {
/*
* Styles the elements projected into a slot element. NOTE: the spec only allows
* styling the direcly slotted elements. Children of those elements are not stylable.
*/
}
Stili di condivisione
Lit semplifica la condivisione degli stili tra i componenti sotto forma di CSSTemplateResults
tramite i tag di modello css
. Ad esempio:
// typography.ts
export const body1 = css`
.body1 {
...
}
`;
// my-el.ts
import {body1} from './typography.ts';
@customElement('my-el')
class MyEl Extends {
static get styles = [
body1,
css`/* local styles come after so they will override bod1 */`
]
render() {
return html`<div class="body1">...</div>`
}
}
Applicazione tema
Le radici ombre rappresentano una sfida per i temi convenzionali, che in genere sono approcci ai tag in stile dall'alto verso il basso. Il modo convenzionale per affrontare la tematizzazione con i componenti web che utilizzano Shadow DOM è esporre un'API di stile tramite le proprietà personalizzate CSS. Ad esempio, questo è un pattern utilizzato da Material Design:
.mdc-textfield-outline {
border-color: var(--mdc-theme-primary, /* default value */ #...);
}
.mdc-textfield--input {
caret-color: var(--mdc-theme-primary, #...);
}
L'utente cambierà il tema del sito applicando i valori delle proprietà personalizzate:
html {
--mdc-theme-primary: #F00;
}
html[dark] {
--mdc-theme-primary: #F88;
}
Se i temi dall'alto verso il basso sono indispensabili e non riesci a esporre gli stili, puoi sempre disattivare DOM shadow sostituendo createRenderRoot
per restituire this
. In questo modo, il modello dei componenti verrà visualizzato nell'elemento personalizzato stesso anziché in una radice shadow collegata all'elemento personalizzato. Con questo andranno persi: l'incapsulamento degli stili, l'incapsulamento del DOM e gli slot.
Produzione
IE 11
Se devi supportare browser meno recenti come IE 11, dovrai caricare alcuni polyfill che escono per circa altri 33 kB. Ulteriori informazioni sono disponibili qui.
Bundle condizionali
Il team di Lit consiglia di pubblicare due diversi bundle, uno per IE 11 e uno per i browser moderni. Questo approccio offre diversi vantaggi:
- La distribuzione di ES 6 è più rapida e serve alla maggior parte dei tuoi clienti
- ES 5 traspilato aumenta significativamente le dimensioni dei bundle
- I pacchetti agevolati ti offrono il meglio di entrambi i mondi
- Supporto di IE 11
- Nessun rallentamento sui browser moderni
Maggiori informazioni su come creare un bundle con pubblicazione condizionale sono disponibili sul nostro sito della documentazione qui.