Lewati ke konten
create-nextjs-kit

Membuat modul

Setiap modul harus punya alasan satu kalimat. Jangan menambah modul karena “lengkap”.

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 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.

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.

  • 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 di test/scaffold.test.ts).
  • Sertakan test untuk kode yang disalin ke proyek.
Terminal window
pnpm test
pnpm build
pnpm 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.