back to top

Da Vue 2 a Vue 3: come creare una nuova applicazione

Nel corso delle precedenti lezioni abbiamo illustrato i concetti chiave di Vue usando la versione 2.6 del framework.

La versione 3 di Vue.js è stata ufficialmente rilasciata a settembre 2020 e le principali novità introdotte riguardano cambiamenti interni atti a migliorare le prestazioni generali e perfezionare il supporto a TypeScript.

Non si tratta dunque di cambiamenti radicali come avvenuto per esempio con Angular. Quanto visto finora in Vue 2 resta perfettamente valido anche per l’ultima versione a parte alcuni cambiamenti marginali che andremo ad analizzare nelle prossime lezioni.

Bisogna comunque evidenziare che Vue 2 è presente in numerossisimi progetti e ci vorrà molto tempo prima che tutti possano essere aggiornati alla nuova versione. Il team di Vue ha inoltre previsto di rilasciare in futuro la versione 2.7 come aggiornamento minore di Vue 2.x. Questa sarà offerta come versione LTS (long-term support) per 18 mesi e saranno garantiti gli aggiornamenti di sicurezza critici per questa versione anche dopo questo periodo.

Nel corso di questa e delle prossime lezioni andremo a presentare alcune delle novità introdotte come Teleport e Fragment. Abbiamo già visto che in Vue 3 ha fatto il suo esordio la Composition API che rappresenta probabilmente la funzione più attesa. Ricordiamo che si tratta di un modo nuovo del tutto opzionale per definire dei componenti. Al contrario dell’esempio esposto qualche lezione fa, in Vue 3 non è più necessario alcun plugin.

Rilascio a fasi della nuova versione

In uno dei passaggi chiave delle note di rilascio viene evidenziato che alcuni dei progetti collegati potrebbero necessitare di tempo prima di raggiungere un completo stato stabile.

Per esempio, al momento in cui stiamo scrivendo questa lezione, la versione 4.5.8 di Vue CLI offre la possibilità di creare un nuovo progetto sia con Vue 2 che con l’ultima versione.

Schermata del terminale di Vue CLI

Dell’estensione Vue Dev Tools, che abbiamo più volte usato nelle precedenti lezioni e che rappresenta uno strumento indispensabile per la fase di debugging, è stata rilasciata una nuova versione, attualmente in fase beta, che consente di rilevare le applicazioni che utilizzano Vue 3.

Altri progetti come Vue Router e Vuex stanno per essere finalizzati per il rilascio delle nuove versioni definitive.

Prima di procedere con il resto delle lezioni è quindi opportuno assicurarsi di aver aggiornato Vue CLI.

npm install -g  @vue/cli @vue/cli-service-global

E aver scaricato l’ultima versione Beta di Vue Dev Tools per Chrome (o simili) o Firefox. Ulteriori informazioni sono disponibili sulla pagina GitHub del progetto.

Vue sta quindi completando la fase di transizione verso la nuova versione, ma al momento della stesura di questa lezione, la versione corrente del framework su NPM è ancora la 2.6, mentre la 3.0.2 è stata rilasciata con l’etichetta next.

elenco versioni di vue.js su npm.com

Per questo motivo, negli esempi che vedremo, potremo dover scaricare l’ultima versione di Vue usando tale etichetta che potrebbe non essere più necessaria nei prossimi mesi.

Come creare una nuova applicazione in Vue 3

Sebbene non siano stati apportati cambiamenti eccessivi in Vue 3, bisogna evidenziare l’introduzione di alcune modifiche significative nell’API.

In particolare è stato introdotta una nuova funzione per la creazione di un’istanza base di un’applicazione, ovvero createApp().

In Vue 2 creiamo delle istanze base di tipo Vue attraverso new Vue().

In Vue 3 invece viene introdotto il concetto di istanza dell’applicazione, un nuovo oggetto globale che prende il posto dell’istanza base di tipo Vue e sul quale andremo ad effettuare tutte quelle operazioni che modificano globalmente il comportamento dell’applicazione.

Per esempio, se prima registravamo un componente o una direttiva globalmente con Vue.component() e Vue.directive(), ora invocheremo dei metodi omonimi, ma sull’istanza globale dell’applicazione.

Vediamo allora un semplice esempio per capire in termini pratici cosa cambia. Per farlo, realizzeremo una banale applicazione la quale mantiene al suo interno il valore di un contatore che andremo ad incrementare con un pulsante per poi mostrare il suo valore aggiornato.

Partiamo realizzando l’applicazione in Vue 2 e poi modifichiamo il codice per renderlo compatibile con Vue 3. Per semplicità in questo primo esempio non useremo Vue CLI, ma ci limiteremo ad includere il codice sorgente di Vue in un file index.html attraverso un elemento di tipo <script>

All’interno di una nuova cartella creiamo allora due file index.html e app.js come mostrato sotto.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Semplice contatore in Vue 2</title>
</head>
<body>
  <div id="app">
    <p class="counter-display">
      {{ counter }}
    </p>
    <simple-button @increment="increment"></simple-button>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
  <script src="app.js"></script>
</body>
</html>

Nel file index.html, riportato sopra, includiamo Vue 2 ed importiamo app.js. Creiamo poi un elemento <div> con id pari ad app che rappresenta il punto d’ingresso dell’applicazione. Tramite interpolazione mostriamo il valore del contatore e aggiungiamo un componente <simple-button>, registrato globalmente, che emette un evento personalizzato increment.

Nel file app.js creiamo una nuova istanza base di Vue a cui passiamo un oggetto di opzioni.

Vue.component('simple-button', {
  template: `
    <button @click="$emit('increment')">Increment</button>
  `
});

const vm = new Vue({
  el: '#app',
  data: {
    counter: 0
  },
  methods: {
    increment() {
      this.counter++;
    }
  }
})

Tramite la proprietà el colleghiamo l’istanza base al template HTML ed indichiamo che l’elemento radice dell’applicazione ha id pari ad ‘app’.

Definiamo poi una proprietà counter che mantiene il valore corrente del contatore. Notate che data è un oggetto.

Abbiamo infine aggiunto un metodo increment() che verrà invocato in risposta all’omonimo evento personalizzoto emesso dal componente <SimpleButton>.

Quest’ultimo è stato registrato globalmente prima di creare l’istanza base attraverso Vue.component(). <SimpleButton> è stato definito tramite un oggetto di opzioni che comprende solamente la proprietà template in cui è presente un pulsante che, se cliccato, emette l’evento personalizzato increment.

Possiamo visualizzare la nostra applicazione funzionante aprendo il file index.html nel browser. Nel nostro caso abbiamo precedentemente installato il package NPM Live Server globalmente con il comando npm i -g live-server. Per questo motivo possiamo aprire il terminale e all’interno della cartella che contiene il file index.html eseguiamo il comando live-server il quale avvia un server locale. Avviamo quindi il browser e digitiamo l’indirizzo http://127.0.0.1:8080 per vedere il risultato finale.

Vue 2 counter app

Completato l’esempio in Vue 2, illustriamo ora come modificarlo ed adattarlo alle novità introdotte in Vue 3.

Il file index.html resta sostanzialmente invariato, dovremo solo sostituire la versione di Vue da includere. Seguendo le indicazioni della documentazione, andremo ad importare Vue 3 cambiando il valore dell’attributo src dell’elemento <script> (useremo l’etichetta @next in base a quanto abbiamo anticipato sopra).

<script src="https://unpkg.com/vue@next"></script>

Avendo importato Vue 3, l’applicazione smette di funzionare dato che dobbiamo ancora modificare il file app.js.

Prima di tutto dovremo creare l’istanza base dell’applicazione e per farlo useremo la nuova funzione Vue.createApp(), disponibile in Vue 3, a cui passeremo un oggetto di opzioni.

const app = Vue.createApp({
  data() {
    return { counter: 0 };
  },
  methods: {
    increment() {
      this.counter++;
    },
  },
});

Notiamo subito delle differenze sostanziali:

  • in Vue 3, data() deve sempre essere un metodo. Non può essere un oggetto come avveniva con l’istanza base in Vue 2
  • Non è più presente la proprietà el per indicare l’elemento base dell’applicazione a partire dal quale assume il controllo il framework

In particolare, per indicare il punto d’ingresso dell’applicazione invocheremo invece il metodo mount() dell’istanza base dell’applicazione. A tale metodo passeremo il selettore che identifica un certo elemento del DOM.

app.mount("#app");

A questo punto ci resta solo da vedere come registrare globalmente il componente SimpleButton.

Anche in questo caso invocheremo il metodo component() dell’istanza base a cui passiamo come primo argomento il nome del componente e come secondo un oggetto di opzioni.

app.component("simple-button", {
  emits: ["increment"],
  template: `
    <div>Clicca sul pulsante per incrementare il contatore</div>
    <br/>
    <button @click="$emit('increment')">Increment</button>
  `,
});

Notiamo due importanti differenze rispetto all’esempio visto in precedenza con Vue 2.

Vue 3 permette di aggiungere una nuova opzione emits che ha lo stesso ruolo della proprietà props, ma per gli eventi. In questo modo sarà possibile documentare meglio un componente. Nell’esempio indichiamo chiaramente che il componente emetterà un evento personalizzato ‘increment’. Più in generale alla proprietà ‘emits‘ assegneremo un array di stringhe in cui ogni elemento rappresenta un evento personalizzato.

È inotre possibile validare gli eventi emessi attraverso delle funzioni. Maggiori dettagli sono disponibili sulla documentazione ufficiale di Vue 3.

La seconda differenza fondamentale è data dal fatto che il template presenta tre elementi radice. Se avessimo usato lo stesso template nell’esempio con Vue 2, avremmo visualizzato un messaggio di errore nella console e avremmo dovuto racchiudere i tre elementi in un solo elemento base. In Vue 2 non era infatti possibile avere più di un elemento radice nel template.

<!-- Template in Vue 2 con un solo elemento wrapper come nodo base -->
  <div>
    <div>Clicca sul pulsante per incrementare il contatore</div>
    <br/>
    <button @click="$emit('increment')">Incrementa</button>
  </div>

Al contrario in Vue 3, i componenti possono avere dei template con più di un nodo base senza dover utilizzare un elemento wrapper superfluo.

<!-- Template in Vue 3 senza elemento wrapper come nodo base -->
<div>Clicca sul pulsante per incrementare il contatore</div>
<br/>
<button @click="$emit('increment')">Increment</button>

Torneremo sull’argomento dei template multi radice in una prossima lezione e vedremo quali conseguenze comportano e quali accorgimenti deve eventualmente prendere un programmatore nell’utilizzare questa nuova e comoda funzione di Vue 3.

Per concludere questa lezione, riportiamo di seguito il codice completo dei due file app.js e index.html dell’esempio appena visto con Vue 3.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Semplice contatore in Vue 3</title>
</head>
<body>
  <div id="app">
    <p class="counter-display">
      {{ counter }}
    </p>
    <simple-button @increment="increment"></simple-button>
  </div>
  <script src="https://unpkg.com/vue@next"></script>
  <script src="app.js"></script>
</body>
</html>
// file: app.js
const app = Vue.createApp({
  data() {
    return { counter: 0 };
  },
  methods: {
    increment() {
      this.counter++;
    },
  },
});

app.component("simple-button", {
  emits: ["increment"],
  template: `
    <div>Clicca sul pulsante per incrementare il contatore</div>
    <br/>
    <button @click="$emit('increment')">Increment</button>
  `,
});

app.mount("#app");

Conclusioni

In questa lezione abbiamo iniziato ad illustrare alcune delle modifiche apportate all’API globale nella nuova versione di Vue.

Pubblicitร