Pipeline Continuous Integration (CI) pada proyek Nuxt 3 kerap mengalami dua masalah utama: durasi build lambat dan kegagalan validasi TypeScript akibat deklarasi auto-imports belum digenerate. Menjalankan tsc atau vue-tsc langsung di environment headless menghasilkan error seperti Cannot find name 'useFetch' atau referensi missing module terhadap .nuxt/tsconfig.json.

Solusinya terletak pada pemisahan fase type generation menggunakan nuxi prepare, eksekusi nuxi typecheck terisolasi, serta penerapan caching yang tepat pada package manager store dan direktori .nuxt/cache.

Penyebab Gagalnya Type Check Nuxt 3 di Lingkungan CI

Nuxt 3 mengandalkan virtual file system dan deklarasi dinamis untuk fitur auto-import komponen, composables, dan konfigurasi runtime. Semua referensi tipe disimpan di dalam folder lokal .nuxt/, khususnya .nuxt/types/.

Saat repository di-checkout di mesin CI, folder .nuxt/ tidak tersedia karena diabaikan oleh .gitignore. Jika pipeline langsung menjalankan vue-tsc --noEmit, compiler membaca tsconfig.json root yang mengekstensi ./.nuxt/tsconfig.json. Karena file tersebut belum ada, proses type checking langsung crash sebelum kode dievaluasi.

Solusi 1: Generate Virtual Types dengan nuxi prepare

Langkah paling cepat untuk menyiapkan runtime types tanpa memicu bundle Nitro atau Vite adalah menjalankan perintah nuxi prepare. Perintah ini mengompilasi konfigurasi Nuxt, memindai direktori auto-import, lalu menghasilkan seluruh file deklarasi TypeScript di dalam direktori .nuxt.

Tambahkan skrip berikut ke dalam package.json:

{
  "scripts": {
    "postinstall": "nuxt prepare",
    "lint": "eslint .",
    "typecheck": "nuxt typecheck",
    "build": "nuxt build"
  },
  "devDependencies": {
    "vue-tsc": "^2.0.0"
  }
}

Penggunaan lifecycle script postinstall memastikan bahwa setiap kali dependency diinstal via npm ci atau pnpm install di mesin CI, nuxt prepare otomatis dieksekusi.

Peringatan: Pastikan vue-tsc terpasang di devDependencies. Perintah nuxt typecheck adalah wrapper Nuxt yang menginisialisasi types Nuxt lalu memanggil binary vue-tsc di bawahnya. Tanpa dependency ini, eksekusi akan gagal.

Solusi 2: Strategi Caching .nuxt/cache dan Dependency

Menyimpan seluruh folder .nuxt ke dalam cache CI dapat memicu stale builds dan false-positive TypeScript errors antar-commit. Caching harus ditargetkan secara spesifik:

  • Package Manager Cache: Simpan global store pnpm atau ~/.npm berdasarkan hash dari lockfile. Ini memangkas waktu setup dependency dari menit ke hitungan detik.
  • Direktori .nuxt/cache: Direktori ini menyimpan artefak kompilasi internal Nitro dan Webpack/Vite. Caching direktori ini aman dilakukan untuk mempercepat fase nuxt build.
  • Hindari Caching: Jangan menyimpan direktori .nuxt/dist atau .output ke dalam general build cache antar job berbeda untuk memastikan hasil build production selalu deterministik.

Implementasi GitHub Actions Workflow

Berikut adalah konfigurasi GitHub Actions efisien yang memisahkan job secara modular. Eksekusi lint dan typecheck dijalankan paralel, diikuti oleh build hanya jika checks sebelumnya lolos.

name: CI Pipeline

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  setup-and-verify:
    name: Quality Checks
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v4

      - name: Setup pnpm
        uses: pnpm/action-setup@v3
        with:
          version: 9

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'pnpm'

      - name: Install Dependencies
        run: pnpm install --frozen-lockfile

      - name: Run Lint
        run: pnpm run lint

      - name: Run Nuxt Typecheck
        run: pnpm run typecheck

  build:
    name: Production Build
    needs: setup-and-verify
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v4

      - name: Setup pnpm
        uses: pnpm/action-setup@v3
        with:
          version: 9

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'pnpm'

      - name: Cache Nuxt Nitro Cache
        uses: actions/cache@v4
        with:
          path: .nuxt/cache
          key: nuxt-cache-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}-${{ hashFiles('**/*.vue', '**/*.ts') }}
          restore-keys: |
            nuxt-cache-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}-
            nuxt-cache-${{ runner.os }}-

      - name: Install Dependencies
        run: pnpm install --frozen-lockfile

      - name: Build Application
        run: pnpm run build
        env:
          NODE_ENV: production

Mitigasi Kesalahan Umum Auto-Import Type Mismatch

1. Penggunaan Bendera CI yang Melewati Lifecycle Scripts

Jika menggunakan command seperti npm ci --ignore-scripts untuk alasan keamanan, script postinstall tidak akan dieksekusi. Akibatnya direktori .nuxt tidak terbuat. Jika flag tersebut wajib digunakan, masukkan step eksplisit npx nuxi prepare sebelum menjalankan step typecheck atau build.

2. Menjalankan vue-tsc Langsung Tanpa Wrapper Nuxi

Banyak pengembang menulis "typecheck": "vue-tsc --noEmit" di package.json layaknya proyek Vue murni. Pada Nuxt 3, selalu gunakan nuxi typecheck. CLI Nuxt memastikan skema tipe runtime, types dari module pihak ketiga (seperti @pinia/nuxt atau @nuxtjs/tailwindcss), serta virtual imports sinkron sebelum binary compiler membaca source tree.

3. Memory Limit pada Runner Headless

Proses kompilasi TypeScript pada codebase besar dapat menghabiskan alokasi RAM default Node.js pada runner CI (biasanya 7 GB pada GitHub-hosted runners, tetapi lebih kecil pada runner private). Jika terjadi crash dengan pesan JavaScript heap out of memory saat typecheck, naikkan batas alokasi memori melalui environment variable:

env:
  NODE_OPTIONS: "--max-old-space-size=4096"