• parcel
  • vite
  • js
  • esbuild
  • bundler
  • monorepo

Da Parcel a Vite: Una breve storia di una migrazione da 100K LOC

Abbiamo migrato i nostri tre progetti frontend da Parcel a Vite, e il processo è stato... fluido.

Gao
Gao
Founder

La storia di fondo

Abbiamo tre principali progetti frontend in Logto: l'esperienza di accesso, la Console e l'anteprima live. Questi progetti sono tutti in TypeScript, React, e moduli SASS; in totale, contano circa 100K linee di codice.

Abbiamo amato Parcel per la sua semplicità e la configurazione zero. Ricordo ancora il giorno in cui rimasi sbalordito da quanto fosse facile configurare un nuovo progetto con Parcel. Puoi semplicemente eseguire parcel index.html e boom, tutte le dipendenze necessarie vengono installate e il progetto è in esecuzione. Se sei un sviluppatore "esperto", potresti provare la stessa sensazione paragonandolo ai vecchi tempi dell'impostazione con Gulp e Webpack. Parcel è come una bacchetta magica.

La semplicità di Parcel è stata la ragione principale per cui siamo rimasti con lui per così tanto tempo, anche se a volte può essere capriccioso. Ad esempio:

  • Parcel a volte non riusciva a creare il pacchetto del progetto perché non riusciva a trovare alcuni file chunk che erano effettivamente lì.
  • Aveva bisogno di alcune configurazioni hacky per funzionare con la nostra configurazione monorepo.
  • Non supporta MDX 3 nativamente, quindi abbiamo dovuto creare un trasformatore personalizzato per esso.
  • Non supporta i chunk manuali (al momento della stesura, la funzione dei chunk manuali è ancora in fase sperimentale), che va bene nella maggior parte dei casi, ma a volte ne hai bisogno.

Allora perché abbiamo deciso di migrare a qualcos'altro?

  1. Eravamo bloccati con Parcel 2.9.3, che è stato rilasciato a giugno 2023. Ogni volta che veniva rilasciata una nuova versione dopo quella, cercavamo di aggiornarci, ma falliva sempre con errori di build.
  2. L'ultima versione di Parcel era 2.12.0, rilasciata a febbraio 2024. Sebbene vi siano quasi commit giornalieri, non è stata rilasciata nessuna nuova versione da allora.

Qualcuno ha persino aperto una discussione per chiedere se Parcel è morto. La risposta ufficiale è no, Parcel è ancora vivo, ma è in uno stato di stiamo-lavorando-su-una-grande-rifattorizzazione-e-non-c'è-tempo-per-le-rilasci-minori. Per noi, è come una "morte dell'anatra": l'ultima versione che possiamo usare risale a più di un anno fa, e non sappiamo quando sarà rilasciata la prossima versione. Sembra che sia morto, si comporta come se fosse morto, quindi per noi è morto.

Richieste di pull per l'aggiornamento di Parcel

Fidati di me, ci abbiamo provato.

Perché Vite?

Conoscevamo Vite da Vitest. Alcuni mesi fa, ci siamo stancati del supporto ESM di Jest (nei test) e volevamo provare qualcosa di nuovo. Vitest ci ha conquistato con il supporto nativo a ESM e la compatibilità con Jest. Ha un'esperienza per sviluppatori fantastica, ed è alimentato da Vite.

Lo stato attuale

Potresti avere impostazioni diverse nel tuo progetto, ma di solito troverai sostituzioni di plugin poiché l'ecosistema Vite è in piena espansione. Ecco le nostre configurazioni al momento della migrazione:

  • Monorepo: Usiamo gli spazi di lavoro di PNPM (v9) per gestire il nostro monorepo.
  • Modulo: Utilizziamo moduli ESM per tutti i nostri progetti.
  • TypeScript: Utilizziamo TypeScript (v5.5.3) per tutti i nostri progetti con alias di percorso.
  • React: Usiamo React (v18.3.1) per tutti i nostri progetti frontend.
  • Stilizzazione: Usiamo moduli SASS per la stilizzazione.
  • SVG: Usiamo SVG come componenti React.
  • MDX: Abbiamo MDX con Markdown in stile GitHub e supporto per Mermaid.
  • Caricamento lazy: Abbiamo bisogno di caricare in modo lazy alcune delle nostre pagine e componenti.
  • Compressione: Produciamo asset compressi (gzip e brotli) per le nostre build di produzione.

La migrazione

Abbiamo iniziato la migrazione creando un nuovo progetto Vite e sperimentandolo per vedere come funziona. Il processo è stato fluido e la migrazione effettiva ha richiesto solo pochi giorni.

Supporto pronto all'uso

Vite offre supporto pronto all'uso per monorepo, ESM, TypeScript, React e SASS. Abbiamo solo dovuto installare i plugin necessari e le configurazioni per farlo funzionare.

Alias di percorso

Vite ha il supporto integrato per gli alias di percorso, ad esempio, nel nostro tsconfig.json:

Abbiamo solo dovuto aggiungere la stessa risoluzione nel nostro vite.config.ts:

Nota che il percorso di sostituzione dovrebbe essere un percorso assoluto, mentre è relativo alla radice del progetto. In alternativa, puoi utilizzare il plugin vite-tsconfig-paths per leggere gli alias di percorso dal tsconfig.json.

React Fast Refresh e HMR

Sebbene Vite abbia il supporto integrato per HMR, è necessario installare un plugin per abilitare React Fast Refresh. Abbiamo usato il plugin @vitejs/plugin-react fornito dal team di Vite, che offre un ottimo supporto per le funzionalità di React come Fast Refresh:

SVG come componente React

Utilizziamo il plugin vite-plugin-svgr per convertire SVG in componenti React. È semplice come aggiungere il plugin alla configurazione di Vite:

Tuttavia, non abbiamo specificato in base a quale condizione gli SVG dovrebbero essere convertiti in componenti React, quindi tutte le importazioni sono state convertite. Il plugin offre una configurazione predefinita migliore: convertire solo gli SVG che sono stati importati con l'estensione .svg?react. Abbiamo aggiornato di conseguenza le nostre importazioni.

Moduli SASS

Sebbene Vite abbia il supporto integrato per i moduli SASS, c'è una cosa di cui dobbiamo occuparci: come i nomi delle classi sono formattati. Potrebbe essere problematico per gli utenti e per i nostri test di integrazione se i nomi delle classi non sono formattati in modo coerente. La configurazione in una riga nel vite.config.ts può risolvere il problema:

A proposito, Parcel e Vite hanno diversi modi di importare i file SASS:

La sintassi * as, tuttavia, funziona in Vite, ma causerà la perdita di nomi di classe modularizzati quando si utilizzano chiavi dinamiche per accedere all'oggetto styles. Ad esempio:

Supporto MDX

Poiché Vite utilizza Rollup sotto il cofano, possiamo utilizzare il plugin ufficiale @mdx-js/rollup per supportare MDX e i suoi plugin. La configurazione è la seguente:

Il plugin remarkGfm è utilizzato per supportare Markdown in stile GitHub e il plugin rehypeMdxCodeProps è utilizzato per passare le proprietà ai blocchi di codice nei file MDX come fa Docusaurus.

Supporto per Mermaid all'interno di MDX

Vorremmo utilizzare diagrammi Mermaid nei nostri file MDX come se fossero altri linguaggi di programmazione. L'uso dovrebbe essere semplice come altri blocchi di codice:

Dovrebbe essere reso come:

Poiché la nostra app supporta temi chiari e scuri, abbiamo scritto un po' di codice per far funzionare i diagrammi Mermaid con il tema scuro. È stato creato un componente React:

useTheme è un hook personalizzato per ottenere il tema corrente dal contesto. La libreria mermaid è importata in modo asincrono per ridurre le dimensioni di caricamento della pagina iniziale.

Per il blocco di codice nel file MDX, abbiamo un componente unificato per svolgere il lavoro:

Infine, definiamo il provider MDX come segue:

Caricamento lazy

Questa non è una cosa specifica di Vite, vale comunque la pena menzionarla dato che abbiamo aggiornato le nostre pagine per utilizzare il caricamento lazy durante la migrazione, e nulla si è rotto successivamente.

React ha una funzione integrata React.lazy per caricare in modo lazy i componenti. Tuttavia, potrebbe causare alcuni problemi quando stai iterando velocemente. Abbiamo creato una piccola libreria chiamata react-safe-lazy per risolvere i problemi. È un sostituto drop-in per React.lazy e una spiegazione dettagliata può essere trovata in questo post sul blog.

Compressione

C'è un plugin carino chiamato vite-plugin-compression per produrre asset compressi. Supporta sia la compressione gzip che brotli. La configurazione è semplice:

Chunk manuali

Una grande funzionalità di Vite (o dell'underlying Rollup) è i chunk manuali. Mentre React.lazy viene utilizzato per il caricamento lazy dei componenti, possiamo avere un maggiore controllo sui chunk specificando i chunk manuali per decidere quali componenti o moduli dovrebbero essere raggruppati insieme.

Ad esempio, possiamo prima usare vite-bundle-visualizer per analizzare la dimensione del bundle e le dipendenze. Poi possiamo scrivere una funzione appropriata per dividere i chunk:

Server di sviluppo

A differenza della build di produzione, Vite NON raggrupperà il tuo codice sorgente in modalità sviluppo (inclusi dipendenze collegate nello stesso monorepo) e tratterà ogni modulo come un file. Per noi, il browser caricherà centinaia di moduli per la prima volta, il che sembra pazzesco ma in realtà va bene nella maggior parte dei casi. Puoi vedere la discussione qui.

Se è un problema per te, una soluzione alternativa ma non perfetta è elencare le dipendenze collegate nell'opzione optimizeDeps del vite.config.ts:

Ciò "pre-bundle" le dipendenze collegate e rende il server di sviluppo più veloce. Il problema è che HMR potrebbe non funzionare come previsto per le dipendenze collegate.

Inoltre, utilizziamo un proxy che serve i file statici in produzione e instrada le richieste al server Vitest in fase di sviluppo. Abbiamo configurato alcune porte specifiche per evitare conflitti, ed è anche facile configurarlo nel vite.config.ts:

Variabili d'ambiente

A differenza di Parcel, Vite utilizza un approccio moderno per gestire le variabili d'ambiente utilizzando import.meta.env. Caricherà automaticamente i file .env e sostituirà le variabili nel codice. Tuttavia, richiede che tutte le variabili d'ambiente siano prefissate con VITE_ (configurabile).

Mentre utilizzavamo Parcel, semplicemente sostituiva le variabili process.env senza controllare il prefisso. Quindi abbiamo trovato una soluzione temporanea utilizzando il campo define per facilitare la migrazione:

Questo ci consente di aggiungere gradualmente il prefisso alle variabili d'ambiente e rimuovere il campo define.

Conclusione

Ecco fatto! Abbiamo migrato con successo i nostri tre progetti frontend da Parcel a Vite e speriamo che questa breve storia possa aiutarti nella tua migrazione. Ecco come appare la configurazione alla fine: