🤖 INFO: La versione 1.0 contiene una monorepo stabile configurata per contenere al suo interno un numero di progetti Vue pari a 1.
Nel branchmaster
(quello da clonare) si trova la versione stabile della monorepo, mentre nel branchdevelop
si trova la monorepo in fase di sviluppo per il successivo rilascio di nuove versioni.
La consultazione di questa repository è consigliata a chi vuole prendere familiarità con:
-**Il gestore di pacchetti pnpm**
-**Vite (for Vue + Typescript projects)**
-**Tailwind CSS**
-**DevExtreme e le sue componenti**
-**Vue router**
-**Pinia**
-**Axsios**
Questa monorepo contiene al suo interno una serie di progetti Vue3
configurati con Vite
.
La gestione dei pacchetti avviene tramite pnpm
.
Se si clona il contenuto della repo l'unico comando da eseguire per farla funzionare è:
> pnpm install
Di seguito invece è mostrata la guida per configurarla partendo da una directory vuota.
La guida prevede tre macro fasi:
- Setup;
- aggiunta configurazioni di librerie comuni utilizzate dai più progetti;
- aggiunta componenti vue riutilizzabili tra i progetti.
Attraverso i comandi:
> pnpm init
> git init
Genero il file package.json
nel root-folder gestore del repository principale della mia monorepo.
Il file creato automaticamente avrà la seguente forma:
{
"name": "demo-monorepo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
E con git
chiaramente il la gestione per il controllo della versione.
Per questo motivo creo un file .gitignore
per escudere tuttii file contenutio all'interno delle cartelle node-modules
che possiamo installare localmente nella macchina dove eseguiremo in dev-mode i progetti demo.
La struttura organizzativa della monorepo dovrà essere qualcosa di simile:
demo-monorepo/
├─ @app/
| ├─ Vue projects
│ ├─ ...
├─ packages/
│ ├─ Componenti o file di configurazione comuni
│ ├─ ...
├─ .gitignore
├─ package.json
├─ ... altri file di root
Creando un file pnpm-workspace.yaml
andiamo a specificare al nostro gestore che useremo gli spazi di lavoro.
In esso definiamo un paio di percorsi in cui qualsiasi directori che creiamo verrà interpretata come un package autonomo.
Il file avrà la seguente configurazione in base alla struttura organizzativa della monorepo pensarta nel passo 1.1.
packages:
- ./@app/*
- ./packages/*
Attraverso Vite configuro velocemente due progetti vue:
user-manage-app
book-manage-app
In questo mi viene in aiuto il gestore dei pacchetti pnpm
:
> pnpm create vite@latest
La configurazione base dei progetti Vue3 con Vite avranno la seguente configurazione:
√ Select a framework: » Vue
√ Select a variant: » TypeScript
⚠️ PASSI ESEGUITI: Per non essere ripetitivo :) mostro solamente la configurazione iniziale del progettouser-manage-app
. Tuttavia può essere applicata a tutti gli altri progetti presnti nella directory@app
.
📦 VERSIONI DELLE DIPENDENZE: Le versioni quando si genereranno i progetti potrebbero essere diverse`.
Il file generato automaticamente da Vite avrà la seguente forma:
{
"name": "user-manage-app",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vue-tsc && vite build",
"preview": "vite preview"
},
"dependencies": {
"vue": "^3.2.47"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.1.0",
"typescript": "^5.0.2",
"vite": "^4.3.2",
"vue-tsc": "^1.4.2"
}
}
La modifica che andiamo ad effettuare è quella di cambiare il nome del progetto allineandolo alla convenzione utilizzata durante la realizzazione di monorepo:
@[nome_monorepo]/[nome_progetto]
nel nostro caso:
{
"name": "@demo/user-manage-app",
...
}
Il file generato automaticamente da Vite avrà la seguente forma:
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }]
}
Potremmo avere bisogno di questo file per definire alcune configurazionio globali quindi ne copiamo il contenuto e lo incolliamo in un nuovo file tsconfig.json
, che creiamo nella root directory.
Ciò che andiamo ad incollare in questo file sono solo le impostazioni comuni e poi indichamo che queste impostazioni comuni vengono estese da altri file tsconfig.json
presenti nelle directory dei progetti vue:
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
/* References to tsconfig.json of other Vue projects */
"references": [
{
"path": "@app/user-manage-app"
}
]
}
mentre nel file tsconfig.json
del progetto Vue definiamo una proprietà di estensione che prende un percorso verso un'altra configurazione ossia quella definita nella root directory, questo file ora avrà ora il seguente aspetto:
{
"extends":"../../tsconfig.json",
"compilerOptions": {
"composite": true
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }]
}
Nel file package.json
generato nel Passo 1 vado amodificare l'attributo scripts
nel seguente modo:
{
...
"scripts":{
"userapp": "pnpm --filter @demo/user-manage-app"
},
...
}
Aggiungo tanti script quanti sono i progetti Vue nella directory @app, lo scopo di questo script è quello di non dover utilizzare per forza il filtro @[nome_monorepo]/[nome_progetto]
.
Essendo che tutti i progetti inclusi in questa monorepo demo utilizzano TypeScrip voglio spostarno a livello globale in modo da avere un suo versioning coerente tra tutti i progetti in modo da non incorrere in futili problemi di compatibilità.
Quando si vogliono installare i pacchetti a livello di root pnpm
chiede una conferma percapire se non si sta eseguendo quest azione per errore, quindi quando si eseguono questi tipi di comando bisogna aggiungere il flag W.
Il comando è il seguente:
> pnpm add -Dw typescript
Dopo l'esecuzione di questo comando si creerà automaticamente un nuovo file pnpm-lock.yaml
in cui sono presenti i riferimenti alle dipendenze installate a livello di root.
Fatto ciò rimuoviamo le dipendenze di typescript interne ai progetti Vuepresenti nei rispettivi package.json
:
{
...
"devDependencies": {
"@vitejs/plugin-vue": "^4.1.0",
"typescript": "^5.0.2", /*<-- da rimuovere*/
"vite": "^4.3.2",
"vue-tsc": "^1.4.2"
}
...
}
Tutte le configurazioni di librerie comuni a vari progetti presenti nella directory @app devono essere inserite nella directory packages con una sub-directory a loro dedicata in cui andiamo ad esplicitare tutti i file di configurazione necessari.
Tailwind è un framework CSS che per essere abilitato in un qualsiasi progetto Vue ha bisosogno di due file di configurazione:
tailwind.config.js
postcss.config.js
Per ulteriori informazioni consultare la guida per configurare Tailwind in un progetto Vite.
Visto che Tailwind è un framework utilizzato da più progetti nella monorepo demo la sua configurazione sarà a livello di root e poi inclusa nei progetti dove viene utilizzata.
Per fare ciò creiamo una nuova sub-directory in packages a cui daremo un nome intuitivo come tailwind-config.
Al sui interno oltre ai due file di configurazione di tailwind sopra specificati vado ad aggiungere l'mmancabile package.json
per gestire tale configurazione.
Se tutto è fatto correttamente la struttura della monorepo avrà questa forma:
demo-monorepo/
├─ @app/
| ├─ Vue projects
│ ├─ ...
├─ packages/
+ | ├─ tailwind-config
+ | ├─ tailwind.config.js
+ │ ├─ postcss.config.js
+ │ ├─ package.json
+ │
├─ .gitignore
├─ package.json
├─ ... altri file di root
In questo file andiamo a definire il nome del nostro pacchetto come riferimento quando lo andiamo ad importare nei progetti del nostro monorepo.
Il nome del pacchetto segue la stessa sintassi utilizzata per definire i noi dei progetti ossia:
@[nome_monorepo]/[nome_package]
Il punto di partenza perciò sara questo:
{
"name":"@demo/tailwind-config",
"private": "true",
"version": "0.0.0",
}
Con il gestore dei pacchetti pnpm
installo alcune dipendenze con il seguente comando:
> pnpm --filter @demo/tailwind-config add autoprefixer postcss tailwindcss
Installate le dipendenze il file json del nostro pacchetto di configurazione di tailwind avrà il seguente aspetto:
{
"name": "@demo/tailwind-config",
"private": "true",
"version": "0.0.0",
"dependencies": {
"autoprefixer": "^10.4.14",
"postcss": "^8.4.23",
"tailwindcss": "^3.3.2"
}
}
const config = require("./tailwind.config.cjs");
module.exports = {
plugins: {
// Specifying the config is not necessary in most cases, but it is included
// here to share the same config across the entire monorepo
tailwindcss: { config },
autoprefixer: {},
},
};
Nel file di configurazione di Tailwind oltre alle proprietà classiche estendo la proprietà color aggiungendo un nuovo colore alla palette fornita:
La colorazione è denominata board ed è caratterizzata da due colorazioni:
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"**/*/index.html",
"**/*.{js,ts,jsx,tsx,vue}",
],
theme: {
extend: {
colors: {
'board':{
DEFAULT:'#323946',
dark:'#1f242d'
}
}
},
},
plugins: [],
}
Attraverso il gestore dei pacchetti pnpm
includo la mia configurazione newi progetti della monorepo con un comando che ha laseguente sintassi:
⚠️ SINTASSI COMANDO: userapp corrisponde al nome dato al progetto preso in esempio durante il setup della monorepo al passo 3.
pnpm userapp add @demo/tailwind-config@workspace:*
Il risultato che ottengo nel package.json
del progetto user-manage-app
è il seguente:
⚠️ NB: Se la dipendenza viene inserità nella proprietà"dependencies"
spostarla nella proprietàdevDependencies
.
{
"name": "@demo/user-manage-app",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vue-tsc && vite build",
"preview": "vite preview"
},
"dependencies": {
"vue": "^3.2.47"
},
"devDependencies": {
"@demo/tailwind-config": "workspace:^", /* dependencies added */
"@vitejs/plugin-vue": "^4.1.0",
"vite": "^4.3.2",
"vue-tsc": "^1.4.2"
}
}
Ora non ci resta che inserire i file di configurazione di tailwind nel progetto dove vogliamo utlilizzarlo in modo tale che ogni file faccia riferimento al medesimo file presente nella nel package di configurazione.
Il risultato dovrebbe essere questo:
user-manage-app/postcss.config.cjs
module.exports = require('@demo/tailwind-config/postcss.config.cjs')
user-manage-app/tailwind.config.cjs
module.exports = require('@demo/tailwind-config/tailwind.config.cjs')
Ultimo ma non meno importante bisogna ricordarci di importare le direttive di Tailwind nel foglio di stile principale del progetto:
@tailwind base;
@tailwind components;
@tailwind utilities;