Integrasi Vite

Build aset dengan Vite, directive @vite, dan mode hot reload.

Daftar isi

Topik ini membahas cara Laravel mengelola aset frontend melalui Vite, yaitu alat build yang memproses CSS dan JavaScript menjadi berkas siap produksi. Pembahasan mencakup dua berkas konfigurasi utama proyek, directive @vite pada template Blade, mode pengembangan dengan hot reload, serta build untuk produksi. Seluruh perintah dijalankan pada aplikasi catatan sehingga keluaran asli setiap langkah dapat diperiksa.

Peran Vite pada proyek Laravel#

Aset frontend modern jarang berupa satu berkas CSS atau JavaScript yang disalin begitu saja ke browser. Tailwind CSS perlu dikompilasi, JavaScript perlu diperkecil, dan nama berkas perlu diberi hash agar perubahan tidak terjebak cache browser. Vite adalah build tool yang mengerjakan ketiganya, dan kerangka proyek Laravel menyertakan konfigurasi Vite sebagai bagian bawaannya sehingga tidak ada pemasangan manual yang diperlukan.

Dua berkas menjadi pusat integrasi ini. Berkas package.json mencatat dependensi JavaScript beserta perintah npm yang tersedia, sedangkan vite.config.js menetapkan cara Vite memproses proyek. Isi keduanya pada aplikasi catatan adalah berikut.

json package.json
{
    "$schema": "https://www.schemastore.org/package.json",
    "private": true,
    "type": "module",
    "scripts": {
        "build": "vite build",
        "dev": "vite"
    },
    "devDependencies": {
        "@tailwindcss/vite": "^4.0.0",
        "concurrently": "^10.0.3",
        "laravel-vite-plugin": "^3.1",
        "tailwindcss": "^4.0.0",
        "vite": "^8.0.0"
    },
    "optionalDependencies": {
        "@laravel/multiplex": "^0.4.1"
    }
}

Bagian scripts mendefinisikan dua perintah yang digunakan sepanjang topik ini, yaitu npm run dev untuk mode pengembangan dan npm run build untuk produksi. Konfigurasi Vite bawaan proyek adalah berikut.

js Konfigurasi vite.config.js bawaan proyek aplikasi catatan
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import { bunny } from 'laravel-vite-plugin/fonts';
import tailwindcss from '@tailwindcss/vite';

export default defineConfig({
    plugins: [
        laravel({
            input: ['resources/css/app.css', 'resources/js/app.js'],
            refresh: true,
            fonts: [
                bunny('Instrument Sans', {
                    weights: [400, 500, 600],
                }),
            ],
        }),
        tailwindcss(),
    ],
    server: {
        watch: {
            ignored: ['**/storage/framework/views/**'],
        },
    },
});

Plugin laravel-vite-plugin menghubungkan Vite dengan Laravel. Kunci input mendaftarkan entry point, yaitu berkas sumber yang menjadi titik masuk build, sedangkan refresh: true membuat browser memuat ulang halaman ketika template Blade berubah. Dependensi yang tercantum pada devDependencies baru tersedia setelah penginstalan, dan langkah tersebut memerlukan Node.js serta npm yang terpasang di sistem.

bash
# memeriksa versi Node.js dan npm yang terpasang
node --version
npm --version
text Keluaran
v24.22.2
11.19.1

Directive @vite dan cara kerjanya#

Template Blade tidak menuliskan tag link dan script secara manual. Directive @vite menerima daftar entry point dan menghasilkan seluruh tag yang dibutuhkan. Layout berikut memuat CSS dan JavaScript aplikasi catatan dengan satu baris directive.

blade layout.blade.php
<!DOCTYPE html>
<html lang="id">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Aplikasi catatan</title>
    @vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body>
    <main class="mx-auto max-w-2xl p-6">
        {{ $slot }}
    </main>
</body>
</html>

Saat template dikompilasi, directive tersebut diubah menjadi pemanggilan objek Vite milik framework.

php Kompilasi directive @vite oleh Blade
// tidak-dijalankan
<?php echo app('Illuminate\Foundation\Vite')(['resources/css/app.css', 'resources/js/app.js']); ?>

Objek Vite menentukan URL setiap aset dari dua sumber yang berlaku menurut kondisi. Apabila berkas public/hot ada, dev server Vite sedang berjalan dan URL merujuk ke server itu. Apabila berkas tersebut tidak ada, URL dibaca dari public/build/manifest.json, yaitu peta antara entry point dan berkas hasil build. Apabila manifest tidak ditemukan, resolusi gagal dengan error yang jelas. Contoh berikut meminta aset dari direktori build-uji yang memang tidak pernah ada, sehingga error-nya dapat direproduksi kapan saja tanpa menyentuh direktori build milik proyek.

bash
# merender directive @vite saat manifest build tidak ditemukan
cd ~/aplikasi-catatan
php artisan tinker --execute='
use Illuminate\Foundation\Vite;
echo app(Vite::class)(["resources/css/app.css"], "build-uji") . PHP_EOL;
'
text Keluaran
   Illuminate\Foundation\ViteManifestNotFoundException  Vite manifest not found at: public/build-uji/manifest.json.

ViteManifestNotFoundException semacam ini juga muncul pada proyek yang baru disalin dari repository tanpa langkah npm apa pun, karena public/build/manifest.json memang belum ada sebelum build dijalankan. Perbaikannya dibahas pada bagian akhir topik.

Mode pengembangan dengan hot reload#

Pengembangan dimulai dengan menginstal dependensi JavaScript yang tercantum pada package.json, lalu menjalankan dev server Vite.

bash
# tidak-dijalankan
# menginstal dependensi JavaScript lalu menjalankan dev server Vite
cd ~/aplikasi-catatan
npm install
npm run dev

Dev server berjalan terus sampai dihentikan dengan Ctrl+C, sehingga perintahnya tidak dieksekusi ulang di sini. Selama server aktif, Vite menulis URL dev server ke berkas public/hot dan Laravel menggunakan URL itu untuk seluruh tag aset. Keluaran sungguhan dari satu percobaan pemasangan dependensi dan pengoperasian server pada salinan proyek adalah berikut.

text Hasil perintah npm install dan npm run dev
added 96 packages, and audited 103 packages in 16s

41 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

> dev
> vite

  VITE v8.3.5  ready in 252 ms

  ➜  Local:   http://localhost:5173/

Dengan dev server aktif, pemanggilan directive yang sama menghasilkan tag yang merujuk langsung ke berkas sumber.

bash
# tidak-dijalankan
# merender tag @vite selama dev server berjalan
cd ~/aplikasi-catatan
php artisan tinker --execute='
use Illuminate\Foundation\Vite;
echo app(Vite::class)(["resources/css/app.css", "resources/js/app.js"]) . PHP_EOL;
'

Keluaran render dari percobaan dengan dev server aktif adalah berikut.

text Hasil render @vite selama dev server aktif
<script type="module" src="http://[::1]:5173/@vite/client"></script><link rel="stylesheet" href="http://[::1]:5173/resources/css/app.css" /><script type="module" src="http://[::1]:5173/resources/js/app.js"></script>

Tag pertama memuat @vite/client, yaitu skrip kecil yang membuka koneksi ke dev server. Dua tag berikutnya memuat CSS dan JavaScript langsung dari berkas sumber tanpa proses build. Ketika berkas sumber disimpan, browser menerima modul terbaru hampir seketika tanpa muat ulang halaman, mekanisme yang disebut hot module replacement. Mode inilah yang dimaksud hot reload pada judul bagian ini.

Build untuk produksi#

Untuk lingkungan produksi, aset dibangun dengan perintah npm run build. Vite mengompilasi setiap entry point, memperkecil berkasnya, memberi hash pada nama berkas, lalu menulis hasilnya ke public/build bersama manifest-nya.

bash
# tidak-dijalankan
# membangun aset untuk lingkungan produksi
cd ~/aplikasi-catatan
npm run build

Keluaran sungguhan dari satu percobaan build pada salinan proyek adalah berikut. Baris kedua adalah catatan plugin font opsional, bukan error.

text Hasil perintah npm run build
vite v8.3.5 building client environment for production...
[plugin laravel:fonts] Optimized font fallbacks require the optional "fontaine" package. Install it, or set "optimizedFallbacks: false" on your fonts to disable the feature.
transforming...
✓ 3 modules transformed.
rendering chunks...
computing gzip size...
public/build/manifest.json                                      1.47 kB │ gzip:  0.33 kB
public/build/fonts-manifest.json                                5.74 kB │ gzip:  0.71 kB
public/build/assets/instrument-sans-400-normal-DRC__1Mx.woff2  16.86 kB
public/build/assets/instrument-sans-500-normal-Dk9ku72i.woff2  17.23 kB
public/build/assets/instrument-sans-600-normal-B7fBEWYG.woff2  17.40 kB
public/build/assets/instrument-sans-400-normal-D1W7dsQl.woff   21.24 kB
public/build/assets/instrument-sans-500-normal-Z6ESRlEs.woff   21.65 kB
public/build/assets/instrument-sans-600-normal-B9e8oLYv.woff   21.67 kB
public/build/assets/fonts-C9MNnjVw.css                          2.35 kB │ gzip:  0.38 kB
public/build/assets/app-XwIzoTLe.css                           53.89 kB │ gzip: 11.56 kB
public/build/assets/app-BvRk9kiK.js                             0.00 kB │ gzip:  0.02 kB

✓ built in 234ms

Berkas manifest.json memetakan setiap entry point ke berkas hasil build-nya. Dua entri pertamanya adalah berikut.

json Contoh: entri dua entry point pada manifest.json
{
  "resources/css/app.css": {
    "file": "assets/app-XwIzoTLe.css",
    "name": "app",
    "names": [
      "app.css"
    ],
    "src": "resources/css/app.css",
    "isEntry": true
  },
  "resources/js/app.js": {
    "file": "assets/app-BvRk9kiK.js",
    "name": "app",
    "src": "resources/js/app.js",
    "isEntry": true
  }
}

Dengan manifest tersedia, directive @vite menghasilkan tag yang merujuk berkas ber-hash tersebut.

bash
# tidak-dijalankan
# merender tag @vite setelah build produksi selesai
cd ~/aplikasi-catatan
php artisan tinker --execute='
use Illuminate\Foundation\Vite;
echo app(Vite::class)(["resources/css/app.css", "resources/js/app.js"]) . PHP_EOL;
'

Keluaran render dari percobaan setelah build adalah berikut.

text Hasil render @vite setelah build produksi
<link rel="preload" as="style" href="http://localhost:8000/build/assets/app-XwIzoTLe.css" /><link rel="modulepreload" as="script" href="http://localhost:8000/build/assets/app-BvRk9kiK.js" /><link rel="stylesheet" href="http://localhost:8000/build/assets/app-XwIzoTLe.css" /><script type="module" src="http://localhost:8000/build/assets/app-BvRk9kiK.js"></script>

Tag yang dihasilkan mencakup pemuatan awal (preload) untuk CSS dan JavaScript, tag stylesheet, dan tag script bertipe module. Nama berkas seperti app-XwIzoTLe.css berubah setiap kali isinya berubah, sehingga browser tidak menyajikan versi lama dari cache. Alur dari berkas sumber hingga tag HTML dirangkum pada diagram berikut.

Berkas sumberresources/css/app.cssresources/js/app.jsnpm run buildVite mengompilasi,memperkecil, meng-hashpublic/buildmanifest.json danaset bernama ber-hashDirective @vitemembaca manifest,menghasilkan tag
Alur build aset dari berkas sumber hingga tag HTML

Kesalahan umum#

Kesalahan pertama adalah men-deploy aplikasi tanpa menjalankan npm run build atau tanpa mengunggah direktori public/build. Setiap halaman yang memuat @vite gagal dengan ViteManifestNotFoundException, persis seperti demo pada bagian directive. Perbaikannya adalah menambahkan langkah build pada proses deploy, sebelum aplikasi menerima permintaan.

Kesalahan kedua adalah menyisakan berkas public/hot di server produksi. Berkas tersebut dibuat oleh dev server dan sering tertinggal ketika proses pengembangan dihentikan secara mendadak. Selama berkas itu ada, semua halaman merujuk aset ke http://[::1]:5173, alamat yang hanya berlaku di komputer pengembang, sehingga halaman produksi kehilangan CSS dan JavaScript-nya.

Kesalahan ketiga adalah menyunting berkas hasil build di public/build secara langsung, misalnya memperbaiki warna pada app-XwIzoTLe.css. Perubahan tersebut hilang pada build berikutnya karena seluruh direktori ditulis ulang. Sumber kebenaran tetap berada di resources/, dan setiap perbaikan diakhiri dengan build ulang.

Ringkasan#

  • Laravel memaketkan Vite melalui package.json dan vite.config.js, dengan plugin laravel-vite-plugin sebagai penghubungnya dan dua entry point standar, yaitu resources/css/app.css serta resources/js/app.js.
  • Directive @vite menghasilkan tag HTML dari berkas public/hot saat dev server aktif, atau dari public/build/manifest.json saat produksi.
  • npm run dev memberi hot reload untuk pengembangan, sedangkan npm run build menghasilkan berkas ber-hash beserta manifest untuk produksi.
  • Error ViteManifestNotFoundException berarti manifest yang dituju tidak ada, dan perbaikannya adalah menjalankan build atau memeriksa direktori build yang diminta.

Referensi#

  • Vite — Laravel — Dokumentasi resmi integrasi Vite pada Laravel, termasuk directive @vite, mode pengembangan, dan build produksi.
  • Frontend — Laravel — Gambaran umum tumpukan frontend bawaan Laravel dan perannya di dalam ekosistem.
  • Getting Started — Vite — Dokumentasi resmi Vite mengenai dev server dan proses build.