Skip to content
nullchefo
← Обратно към дневника
2 мин четене

Преизграждане на nullchefo.com с Astro

Защо замених React SPA за острови, content collections и нула JavaScript по подразбиране — и как реално изглеждаше миграцията.

#astro#typescript#meta Налична и на: English

Предишната версия на този сайт беше Next.js приложение. Работеше, но доставяше цял React runtime, за да рендира нещо, което честно казано е документ: малко текст за мен, списък с работни позиции, няколко линка. Новата версия е изградена с Astro и резултатът е чист HTML и CSS с няколкостотин байта vanilla JS за мобилното меню и scroll анимациите.

Защо Astro

Три причини направиха решението лесно:

  • Нула JS по подразбиране. Компонентите се рендират до HTML по време на билда. JavaScript съществува само там, където изрично го добавя.
  • Content collections. Публикациите са MDX файлове, валидирани от схема по време на билда — правописна грешка в дата е грешка при билда, а не тих бъг в продукция.
  • Всичко е TypeScript. Файловете с данни, помощните функции и шаблоните споделят една типова система. Данните от CV-то ми са типизиран обект, използван и от английските, и от българските страници.

Съдържанието като файлове

Всяка публикация в този сайт живее в папка, кръстена на езика ѝ:

src/content/blog/
├── en/
│   └── rebuilding-nullchefo-with-astro.mdx
└── bg/
    └── rebuilding-nullchefo-with-astro.mdx

Името на папката е локалът. Добавянето на немска версия на тази публикация би означавало създаване на de/rebuilding-nullchefo-with-astro.mdx — нищо друго. Схемата на колекцията държи всички честни:

const blog = defineCollection({
	loader: glob({ pattern: '**/*.mdx', base: './src/content/blog' }),
	schema: z.object({
		title: z.string(),
		description: z.string(),
		pubDate: z.coerce.date(),
		tags: z.array(z.string()).default([]),
		draft: z.boolean().default(false),
	}),
});

Тъй като преводите споделят едно име на файл, страницата на публикацията може сама да открие близнаците си и да направи линк към тях — редът “налична и на” по-горе се генерира от файловата система, а не се поддържа на ръка.

Какво запазих от стария сайт

Данните. Старото портфолио държеше CV съдържанието в TypeScript файлове, които се оказаха най-устойчивата част от кодовата база. Преместиха се почти без промяна, само с по-строги типове и ISO дати, така че всеки локал да форматира периодите по своя начин:

const monthYear = new Intl.DateTimeFormat(localeTag, {
	month: 'short',
	year: 'numeric',
});

Пренаписванията рядко се изплащат заради framework-а. Изплащат се, когато те принудят да отделиш това, което се променя често (съдържанието), от това, което не се променя (рендирането).

Числата

МетрикаNext.js SPAAstro
Доставен JS (начало)~140 KB< 2 KB
Lighthouse perf80-и100
Изход от билдасървърстатичен

Статичният изход означава, че целият сайт се деплойва на всеки хост, който може да сервира файлове — без Node сървър, без cold starts, без нищо за патчване в 2 през нощта.

Stefan Kehayov

Full-stack инженер · Доспат · България