Content Collections & data eksternal
Content Collections dirancang untuk konten yang ada saat build. Portal beritamu tidak seperti itu — tapi ada bagian yang cocok, dan satu fitur baru yang mengubah perhitungannya.
Intisari
- Collection klasik memuat kontennya saat build. Artikel yang terbit sesudahnya tidak ada di sana.
- Sejak Astro 5, semua collection wajib memakai Content Layer API dengan
loader. - Live collections mengambil data saat request — cocok untuk sumber eksternal yang berubah terus.
- Untuk 200 ribu artikel di MySQL, fungsi
src/lib/biasa tetap lebih tepat daripada collection. - Yang cocok jadi collection: halaman statis redaksional, glosarium, profil penulis, dokumen kebijakan.
Apa yang sebenarnya diberikan Content Collections
Tiga hal: skema bertipe dengan Zod, pemuatan dari sumber apa pun lewat loader, dan API kueri yang seragam. Ia dirancang untuk konten yang jumlahnya terkelola dan berubah pada kecepatan manusia — bukan untuk arsip berita ratusan ribu entri.
// src/content.config.ts
import { defineCollection, z } from "astro:content";
import { glob } from "astro/loaders";
const kebijakan = defineCollection({
loader: glob({ pattern: "**/*.md", base: "./src/konten/kebijakan" }),
schema: z.object({
judul: z.string(),
diperbaruiPada: z.coerce.date(),
ringkasan: z.string().optional(),
}),
});
export const collections = { kebijakan };
---
import { getCollection, render } from "astro:content";
export const prerender = true;
export async function getStaticPaths() {
const semua = await getCollection("kebijakan");
return semua.map((e) => ({ params: { slug: e.id }, props: { entri: e } }));
}
const { entri } = Astro.props;
const { Content } = await render(entri);
---
<h1>{entri.data.judul}</h1>
<Content />
Sejak Astro 5, src/content/ tidak lagi ajaib. Semua collection harus dideklarasikan
di src/content.config.ts dengan loader eksplisit. Tutorial yang menyuruhmu
cukup menaruh berkas Markdown di src/content/blog/ ditulis untuk Astro 4 ke bawah dan tidak
akan bekerja.
Loader kustom dari MySQL
// Bisa dilakukan — tapi baca peringatannya di bawah
import type { Loader } from "astro/loaders";
function loaderPenulis(): Loader {
return {
name: "penulis-mysql",
load: async ({ store, parseData, logger }) => {
const baris = await dbBaca
.selectFrom("member")
.select(["id", "nama", "bio", "foto"])
.where("peran", "in", ["penulis", "editor"])
.execute();
store.clear();
for (const p of baris) {
const data = await parseData({ id: String(p.id), data: p });
store.set({ id: String(p.id), data });
}
logger.info(`memuat ${baris.length} penulis`);
},
};
}
Ini masuk akal untuk penulis: jumlahnya puluhan, berubah jarang, dan halaman profilnya layak di-prerender. Ini tidak masuk akal untuk artikel: 200 ribu entri akan dimuat ke penyimpanan collection setiap build, dan artikel baru tetap butuh build ulang untuk muncul.
Live collections — yang mengubah perhitungan
Astro punya live content collections yang mengambil data saat request, bukan saat build. Ini menutup celah untuk sumber eksternal yang berubah terus:
// src/live.config.ts
import { defineLiveCollection } from "astro:content";
import { loaderDataPasar } from "@/lib/loader-pasar";
export const collections = {
pasar: defineLiveCollection({ loader: loaderDataPasar() }),
};
---
import { getLiveCollection } from "astro:content";
export const prerender = false;
const { entries, error } = await getLiveCollection("pasar");
if (error) {
console.error(error);
}
---
{entries?.map((e) => <BarisPasar data={e.data} />)}
Fitur ini masih di balik flag eksperimental. Artinya API-nya bisa berubah di rilis minor, dan
memakainya untuk jalur kritis portalmu berarti menerima risiko itu. Untuk kasus yang jelas — mengambil
data dari MySQL atau API — fungsi biasa di src/lib/ plus cache dari materi sebelumnya
memberi hasil yang sama dengan kendali penuh dan tanpa risiko API berubah. Ketahui bahwa fiturnya ada;
jangan jadikan fondasi.
Peta keputusan untuk portalmu
| Konten | Pakai | Alasan |
|---|---|---|
| Artikel berita (200rb) | Kysely + src/lib/ | Terlalu banyak, berubah terus, butuh kueri kompleks |
| Data perusahaan | Kysely + src/lib/ | Sama |
| Profil penulis | Collection dengan loader MySQL | Puluhan, jarang berubah, layak di-prerender |
| Kebijakan privasi, S&K, panduan gaya | Collection + Markdown | Ditulis manusia, di-review lewat PR, versinya terlacak git |
| Glosarium istilah pasar | Collection + Markdown | Sama |
| Halaman kampanye langganan | Collection + Markdown | Marketing bisa menyuntingnya lewat PR tanpa menyentuh kode |
| Data pasar real-time | Fungsi + cache pendek | Live collection masih eksperimental |
Pola yang muncul: collection untuk konten yang hidup di git; fungsi lib/ untuk data
yang hidup di database. Itu pembagian yang bertahan.
Baris kebijakan privasi itu lebih berguna dari kelihatannya. Di CI3, halaman seperti ini
biasanya berakhir sebagai baris di tabel halaman_statis yang disunting lewat panel admin —
tanpa riwayat, tanpa review, tanpa cara mengetahui siapa mengubah apa. Sebagai Markdown di git, tiap
perubahan punya penulis, tanggal, dan diff. Untuk dokumen yang punya konsekuensi hukum, itu peningkatan
nyata.
Latihan: buat collection kebijakan dari berkas Markdown dengan skema Zod berisi
judul dan diperbaruiPada, lalu render satu halaman dari sana dengan
prerender = true. Sengaja hilangkan field judul dari salah satu berkas dan
jalankan pnpm build — pastikan build gagal dengan pesan yang menyebut berkas dan field-nya.
Itu perilaku yang kamu inginkan untuk dokumen kebijakan.
Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.