Membuat modul
Setiap modul harus punya alasan satu kalimat. Jangan menambah modul karena “lengkap”.
Satu installer per modul
Section titled “Satu installer per modul”Buat packages/create-nextjs-kit/src/installers/<id>.ts, lalu daftarkan di registry.ts:
import type { Installer } from "./types";
export const myModule: Installer = { id: "my-module", label: "My module", hint: "Satu kalimat untuk prompt", modes: ["frontend"], requires: ["api-client"], // opsional, ikut terpasang dan dijalankan lebih dulu conflicts: [], // opsional, tidak boleh bersamaan async apply(ctx) { await ctx.copyExtras("my-module"); // salin template/extras/my-module ke proyek ctx.addDependencies({ "some-lib": "^1.0.0" }); ctx.addScripts({ "my:task": "some-lib run" }); await ctx.insertAtSlot("src/config/env.ts", "env-server", "MY_KEY: z.string(),"); },};Template memakai penanda @slot:<nama> di satu baris komentar. insertAtSlot menyisipkan kode
tepat sebelum penanda, mengikuti indentasinya. Penanda yang tidak terpakai dihapus di akhir.
// @slot:providers# @slot:env-example{/* @slot:body */}Slot yang tersedia di template/base: env-server, env-client, env-runtime, env-example,
providers, providers-imports, instrumentation, next-config, boundaries-elements,
boundaries-policies, vitest-imports, vitest-setup, prettierignore, eslint-ignores, playwright-app-env,
playwright-servers.
Modul boleh menambah slot di file miliknya sendiri, misalnya api-imports di api-client.
API lain di ctx
Section titled “API lain di ctx”| API | Fungsi |
|---|---|
allowBuilds(names) |
Izinkan build script dependency di pnpm 11+ (mis. esbuild) |
replaceInFile(file, teks, pengganti) |
Ganti teks persis milik base; gagal bila muncul 0 atau lebih dari 1 kali |
removeFile(file) |
Hapus file contoh yang digantikan modul |
useCiPostgres({ testDb? }) |
Tambahkan service Postgres dan migrasi ke CI; testDb: true juga menjalankan test:db |
useCiEnv(env) |
Tambahkan variabel environment ke job check dan e2e di CI (nilai khusus CI, bukan rahasia) |
replaceInFile dan removeFile hanya untuk modul yang memang menggantikan bagian contoh milik
base (seperti dal menggantikan penyimpanan di memori). Untuk menambah kode, tetap pakai slot.
Integrasi antar modul
Section titled “Integrasi antar modul”Perilaku yang hanya ada pada kombinasi tertentu (mis. todos per pengguna bila dal dan auth
dipasang bersama) ditaruh di integrasi, bukan di salah satu modul, supaya tidak ada modul yang
perlu tahu soal modul lain. Buat src/installers/integrations/<a>-<b>.ts, daftarkan di
integrations/index.ts, dan taruh filenya di template/extras/integrations/<a>-<b>/:
export const dalAuth: Integration = { id: "dal-auth", when: ["dal", "auth"], // aktif hanya bila SEMUA modul ini terpilih async apply(ctx) { await ctx.copyExtras("integrations/dal-auth"); await ctx.replaceInFile("src/config/auth.ts", "...", "..."); },};Integrasi berjalan setelah semua modul dan boleh mengganti file milik modul-modul yang
dihubungkannya. Yang aktif dicatat di nextjs-kit.json (integrations). Setiap kombinasi perlu
migrasi dan E2E sendiri; matriks smoke-db di CI menguji kombinasi yang ada.
Aturan
Section titled “Aturan”- Installer hanya menambah atau menyisipkan. Jangan menulis ulang file milik installer lain.
Satu pengecualian: modul yang menggantikan contoh milik base boleh memakai
replaceInFile. - Hasil generate tidak boleh bergantung pada paket ini saat runtime.
- Tidak boleh ada
@slot:atau__PROJECT_NAME__tersisa (dicek ditest/scaffold.test.ts). - Sertakan test untuk kode yang disalin ke proyek.
Verifikasi
Section titled “Verifikasi”pnpm testpnpm buildpnpm smoke --mode frontend --preset <preset>pnpm smoke meng-generate proyek, meng-install, lalu menjalankan typecheck, lint, format check,
test, dan build. Wajib lolos sebelum PR yang menyentuh template/ atau installer.