Automatizza build e deploy con GitHub Actions

Creare una pipeline CI/CD con GitHub Actions per una app Node + React

Tutorial pratico per creare una pipeline CI/CD con GitHub Actions per una app Node e React: build, test, deploy automatico e rollback.

Automatizzare il ciclo di vita dello sviluppo è fondamentale. In questa guida pratica, vedremo come implementare una pipeline CI/CD GitHub Actions Node React per buildare, testare e deployare un’applicazione full-stack in modo efficiente e sicuro, riducendo gli errori manuali e accelerando il time-to-market.

Il Problema: Deploy Manuali, Rischiosi e Lenti

Ogni sviluppatore conosce la routine: modificare il codice, eseguire test in locale, fare il build e poi caricare manualmente i file sul server via FTP o SSH. Questo processo non solo è lento, ma è anche estremamente prono a errori umani che possono causare downtime e frustrazione.

La soluzione è l’automazione. Una pipeline di Continuous Integration (CI) e Continuous Deployment (CD) esegue questi passaggi automaticamente ad ogni push sul repository, garantendo coerenza, velocità e affidabilità.

Prerequisiti per la Pipeline

Prima di iniziare, assicurati di avere a disposizione i seguenti elementi:

  • Un account GitHub con un repository contenente un’app Node.js e React.
  • Node.js e npm (o yarn) installati in locale.
  • Una conoscenza di base di Git, Node.js, React e della linea di comando.
  • Un server di destinazione per il deploy (es. una VPS) con accesso SSH.

La Struttura del Workflow in GitHub Actions

GitHub Actions utilizza file di configurazione in formato YAML, che devono essere posizionati nella directory .github/workflows/ del tuo repository. Creeremo un file, ad esempio main.yml, che definirà tutti i passaggi della nostra pipeline.

Il nostro workflow si attiverà ad ogni push sul branch main e sarà composto da diversi “job” che possono essere eseguiti in parallelo o in sequenza.

Schema del workflow della pipeline CI/CD GitHub Actions Node React, dal push al deploy.
Diagramma logico del flusso di lavoro per la nostra pipeline CI/CD con GitHub Actions.

Step 1: Definire il Trigger del Workflow

Il primo passo è definire quando il nostro workflow deve essere eseguito. In questo caso, lo vogliamo avviare ad ogni push sul branch main.


name: Node.js and React CI/CD

on:
  push:
    branches: [ "main" ]
        

Step 2: Job di Build e Test del Frontend (React)

Il primo job si occuperà di verificare l’integrità della nostra applicazione React. Eseguirà l’installazione delle dipendenze, i test e il build di produzione.


jobs:
  build-frontend:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: ./client # Assumendo che il codice React sia in una cartella 'client'
    steps:
    - name: Checkout repository
      uses: actions/checkout@v4

    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: '20'
        cache: 'npm'
        cache-dependency-path: client/package-lock.json

    - name: Install dependencies
      run: npm ci

    - name: Run tests
      run: npm test -- --watchAll=false

    - name: Build application
      run: npm run build
        

Step 3: Job di Build e Test del Backend (Node.js)

In parallelo al job del frontend, possiamo eseguire i controlli per il backend Node.js. Anche qui, installeremo le dipendenze ed eseguiremo i test automatici.


  build-backend:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: ./server # Assumendo che il codice Node sia in una cartella 'server'
    steps:
    - name: Checkout repository
      uses: actions/checkout@v4

    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: '20'
        cache: 'npm'
        cache-dependency-path: server/package-lock.json

    - name: Install dependencies
      run: npm ci

    - name: Run tests
      run: npm test
        

Il Workflow Completo per la pipeline CI/CD GitHub Actions Node React

Ora, mettiamo tutto insieme in un unico file .github/workflows/main.yml, aggiungendo il passo finale di deploy. Il job di deploy dipenderà dal successo dei job di build, usando la direttiva needs.

Per il deploy, useremo un’azione popolare per SSH e SCP, configurando le credenziali come GitHub Secrets per la massima sicurezza.


name: Node.js and React CI/CD

on:
  push:
    branches: [ "main" ]

jobs:
  build-frontend:
    runs-on: ubuntu-latest
    defaults: { run: { working-directory: ./client } }
    steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-node@v4
      with:
        node-version: '20'
        cache: 'npm'
        cache-dependency-path: client/package-lock.json
    - run: npm ci
    - run: npm test -- --watchAll=false
    - run: npm run build
    - name: Upload build artifact
      uses: actions/upload-artifact@v4
      with:
        name: frontend-build
        path: client/build

  build-backend:
    runs-on: ubuntu-latest
    defaults: { run: { working-directory: ./server } }
    steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-node@v4
      with:
        node-version: '20'
        cache: 'npm'
        cache-dependency-path: server/package-lock.json
    - run: npm ci
    - run: npm test

  deploy:
    runs-on: ubuntu-latest
    needs: [build-frontend, build-backend]
    steps:
      - name: Download frontend build
        uses: actions/download-artifact@v4
        with:
          name: frontend-build
          path: client/build

      - name: Deploy to server
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.SSH_HOST }}
          username: ${{ secrets.SSH_USERNAME }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          port: ${{ secrets.SSH_PORT }}
          script: |
            cd /var/www/my-app
            git pull origin main
            # Comandi per riavviare il server Node (es. con PM2)
            # pm2 restart my-app
        

Conclusione: Automazione è Potenza

Abbiamo visto come configurare una pipeline CI/CD GitHub Actions Node React da zero. Questo workflow automatizza i test e il build sia per il frontend che per il backend, per poi gestire il deploy su un server remoto in modo sicuro.

Adottare questo approccio non è un lusso, ma una necessità per i team moderni. Permette di rilasciare nuove funzionalità più velocemente, con maggiore fiducia e con un rischio di errori drasticamente ridotto. Ora tocca a te: adatta questo esempio al tuo progetto e porta il tuo processo di sviluppo al livello successivo.