4
Konfigurasi Build dan Alat Pengembangan
Build di repository ini dijalankan sepenuhnya oleh next. Tidak ada bundler atau task runner terpisah, jadi seluruh pipeline ditentukan oleh empat berkas: next.config.js untuk perilaku build, postcss.config.js untuk rantai CSS, tsconfig.json untuk resolver alias, dan package.json untuk urutan perintah. Pemeriksaan kualitas menumpang pada eslint lewat next lint dan pada prettier lewat lint-staged (package.json:5-191).
Urutan build, postbuild, dan pemeriksaan lint
next build menghasilkan direktori .next, lalu hook postbuild menjalankan next-sitemap untuk membuat sitemap dan robots.txt. Jalur lint, typecheck, dan format:check berdiri sendiri dan tidak dipanggil oleh build; CI yang memanggilnya satu per satu (.github/workflows/lint.yml:34-442).
graph TD
buildScript["pnpm build"] --> nextBuild["next build"]
nextBuild --> webpackHook["webpack(): aturan svg"]
nextBuild --> eslintDirs["eslint.dirs: ['src']"]
nextBuild --> dotNext["output .next"]
dotNext --> postBuild["postbuild: next-sitemap"]
postBuild --> assets["sitemap.xml + robots.txt"]
strictLint["pnpm lint:strict: --max-warnings=0"] -.-> eslintDirs
typecheckRun["pnpm typecheck: tsc --noEmit"] -.-> tsconfigFile["tsconfig.json"]
style buildScript fill:#2d7d46,color:#fff
style nextBuild fill:#2d7d46,color:#fff
style dotNext fill:#2d7d46,color:#fff
style webpackHook fill:#f59e0b,color:#000
style eslintDirs fill:#f59e0b,color:#000
style strictLint fill:#f59e0b,color:#000
style typecheckRun fill:#f59e0b,color:#000
style tsconfigFile fill:#f59e0b,color:#000
style postBuild fill:#8b5cf6,color:#fff
style assets fill:#8b5cf6,color:#fff
%% fig: Urutan build, postbuild, dan pemeriksaan lint
%% desc: next build menghasilkan output .next, kemudian hook postbuild menjalankan next-sitemap; lint dan typecheck berjalan di jalur terpisah.Seluruh perintah tinggal di blok scripts package.json (package.json:5-191):
| Script | Perintah | Fungsi |
|---|---|---|
dev | next dev | server pengembangan |
build | next build | build produksi |
start | next start | menjalankan hasil build |
lint | next lint | ESLint lewat Next |
lint:fix | eslint src --fix && pnpm format | perbaikan otomatis, lalu format |
lint:strict | eslint --max-warnings=0 src | nol warning |
typecheck | tsc --noEmit --incremental false | cek tipe tanpa menulis berkas |
test, test:watch | jest, jest --watch | lihat Pengujian dengan Jest |
format, format:check | prettier -w ., prettier -c . | tulis ulang atau periksa format |
postbuild | next-sitemap --config next-sitemap.config.js | sitemap dan robots.txt |
prepare | husky install | pasang hook git |
⚠️
.npmrchanya berisi satu baris,enable-pre-post-scripts=true(.npmrc:1-1). Tanpa baris itu pnpm tidak menjalankan hookpre/postsecara otomatis, sehinggapostbuildtidak pernah dieksekusi dan sitemap tidak terbentuk. Konfigurasi sitemap sendiri mematoksiteUrl: 'https://tsnext-tw.thcl.dev'dangenerateRobotsTxt: true(next-sitemap.config.js:5-133); nilai itu wajib diganti sebelum deploy, seperti dibahas di SEO, Sitemap, dan Deploy.
next.config.js: eslint, reactStrictMode, dan aturan webpack
nextConfig hanya memuat tiga kunci aktif, sisanya blok images yang masih dikomentari sebagai contoh whitelist domain (next.config.js:9-174).
| Kunci | Nilai | Efek |
|---|---|---|
eslint.dirs | ['src'] | next lint dan pemeriksaan saat next build hanya menyentuh src (next.config.js:3-55) |
reactStrictMode | true | komponen dirender dua kali di mode pengembangan (next.config.js:76) |
webpack | fungsi | menambal aturan svg sebelum config dikembalikan (next.config.js:19-497) |
Fungsi webpack bekerja dalam tiga langkah. Pertama, ia mencari aturan bawaan yang menangani .svg lewat rule.test?.test?.('.svg') (next.config.js:21-238). Kedua, ia mendorong dua aturan baru: salinan aturan lama yang hanya berlaku untuk impor ?url, dan aturan @svgr/webpack untuk semua *.svg lain dengan dimensions: false serta titleProp: true (next.config.js:25-439). Ketiga, aturan lama diberi exclude = /\.svg$/i agar tidak ikut menangani SVG (next.config.js:4610).
Hasilnya, import Logo from '~/svg/Logo.svg' menjadi komponen React yang menerima className (src/app/page.tsx:1811, src/app/page.tsx:2912). titleProp: true berarti prop title diteruskan sebagai elemen <title> di dalam SVG.
postcss.config.js dan Tailwind v4
Rantai CSS hanya berisi dua plugin dengan urutan tetap: @tailwindcss/postcss lebih dulu, lalu autoprefixer (postcss.config.js:1-613). Keduanya terpasang sebagai devDependency bersama postcss dan tailwindcss versi 4 (package.json:53-5614).
Tidak ada tailwind.config.js di akar repository. Pada Tailwind v4, token justru dideklarasikan di CSS lewat blok @theme di src/styles/globals.css, setelah @import 'tailwindcss' dan @plugin '@tailwindcss/forms'. Rincian token warna dan animasinya ada di Styling, Token Warna, dan Tema.
tsconfig.json dan alias path
baseUrl diset "." dengan dua alias: @/* ke ./src/* dan ~/* ke ./public/* (tsconfig.json:16-2015). strict, noEmit, isolatedModules, dan jsx: "preserve" aktif, dan plugins memuat next agar editor memakai tipe framework (tsconfig.json:2-2716). Berkas yang diperiksa adalah next-env.d.ts, seluruh **/*.ts dan **/*.tsx, serta .next/types/**/*.ts yang dibangkitkan Next (tsconfig.json:2817).
Satu alias punya tiga konsumen, dan hanya dua di antaranya membaca tsconfig.json secara langsung:
graph LR
tsPaths["tsconfig.json paths"] --> atAlias["'@/*' ke ./src/*"]
tsPaths --> tildeAlias["'~/*' ke ./public/*"]
atAlias --> tscRun["tsc --noEmit"]
atAlias --> webpackRun["next build, webpack resolver"]
atAlias --> jestMap["jest moduleNameMapper"]
tildeAlias --> jestMap
jestMap --> svgMockFile["src/__mocks__/svg.tsx"]
style tsPaths fill:#f59e0b,color:#000
style atAlias fill:#f59e0b,color:#000
style tildeAlias fill:#f59e0b,color:#000
style tscRun fill:#2d7d46,color:#fff
style webpackRun fill:#2d7d46,color:#fff
style jestMap fill:#8b5cf6,color:#fff
style svgMockFile fill:#8b5cf6,color:#fff
%% fig: Satu alias, tiga konsumen
%% desc: paths di tsconfig.json dipakai tsc dan webpack Next, sedangkan Jest memerlukan moduleNameMapper yang menyalin alias tersebut.⚠️ Menambah alias baru berarti menyentuh dua tempat.
tsconfig.jsonsaja tidak cukup karena Jest memakaimoduleNameMappersendiri (jest.config.js:22-2618); alias yang hanya ada dipathsakan gagal dipnpm testdenganCannot find module.
Satu catatan kecil: moduleResolution sudah bernilai "node" di dalam compilerOptions (tsconfig.json:1219), tetapi kunci bernama sama muncul lagi di level akar, di luar compilerOptions (tsconfig.json:3020).
ESLint
Konfigurasi memakai .eslintrc.js format lama dengan tiga plugin, @typescript-eslint, simple-import-sort, dan unused-imports, yang dirangkai dari eslint:recommended, next, next/core-web-vitals, plugin:@typescript-eslint/recommended, dan prettier (.eslintrc.js:7-1421).
Aturan yang paling terasa saat menulis kode (.eslintrc.js:15-3822):
| Aturan | Nilai | Akibat |
|---|---|---|
no-console | warn | console lolos lint, tetapi gagal lint:strict |
unused-imports/no-unused-imports | warn | impor tak terpakai wajib dibuang |
unused-imports/no-unused-vars | warn | variabel berawalan _ dikecualikan |
@typescript-eslint/no-unused-vars | off | cek impor diserahkan ke unused-imports |
react/jsx-curly-brace-presence | warn | kurung kurawal berlebih di JSX ditolak |
Karena lint:strict memakai --max-warnings=0 (package.json:1123) dan no-console hanya warn, satu console.log sudah cukup menggagalkan lint:strict. Urutan impor dipaksa oleh simple-import-sort/imports dengan sepuluh grup: pustaka eksternal, berkas CSS, @/lib dan @/hooks, @/data, @/components dan @/container, @/store, sisa @/, path relatif, @/types, lalu sisanya (.eslintrc.js:41-7724). React dan JSX didaftarkan sebagai global agar tidak dilaporkan (.eslintrc.js:80-8325).
Prettier
.prettierrc.js hanya menetapkan lima opsi: arrowParens: 'always', singleQuote: true, jsxSingleQuote: true, tabWidth: 2, dan semi: true (.prettierrc.js:1-726). Plugin prettier-plugin-tailwindcss terpasang sehingga kelas Tailwind dirapikan otomatis saat format dijalankan (package.json:5527).
.prettierignore mengecualikan hasil build (.next, /out, /build, /coverage) sekaligus dua berkas yang diurus alat lain, yaitu CHANGELOG.md dan pnpm-lock.yaml (.prettierignore:39-41). Pada tahap lint-staged, berkas js/jsx/ts/tsx melewati eslint --max-warnings=0 lalu prettier -w, sedangkan json/css/scss/md/webmanifest cukup prettier -w (package.json:59-6728). Rangkaian hook git dan CI yang memanggil ini dibahas di Otomasi Repository: Husky, Commitlint, dan CI.
Jest
jest.config.js tidak menulis konfigurasi dari nol: nextJest({ dir: './' }) membungkus config agar next.config.js dan berkas .env ikut termuat di lingkungan test (jest.config.js:4-729). Opsi kustomnya:
| Opsi | Nilai | Fungsi |
|---|---|---|
setupFilesAfterEnv | <rootDir>/jest.setup.js | memuat matcher tambahan |
moduleDirectories | ['node_modules', '<rootDir>/'] | mendukung baseUrl di akar |
testEnvironment | jest-environment-jsdom | DOM untuk Testing Library |
moduleNameMapper | @/, ~/, dan svg | menyalin alias tsconfig.json |
Pemetaan ^.+\.(svg)$ mengarah ke src/__mocks__/svg.tsx (jest.config.js:22-2618), yaitu komponen tiruan yang meneruskan ref dan props ke <svg> polos (src/mocks/svg.tsx:1-8). Dengan begitu impor SVG hasil @svgr/webpack tidak perlu benar-benar ditransformasi saat test. Sementara jest.setup.js memuat @testing-library/jest-dom/extend-expect dan mengganti next/router dengan next-router-mock (jest.setup.js:1-530). Isi test dan pola penulisannya ada di Pengujian dengan Jest.