Как я создал блог и личный сайт на Next.js (Бесплатный хостинг!)

Привет! Я решил создать свой блог и личную страницу. Для блога использовал готовый шаблон, который адаптировал под себя, а личную страницу сверстал с нуля. В этой статье расскажу, как выбирал шаблон, дорабатывал его, придумывал дизайн и верстал сайт. Если ты тоже хочешь сделать что-то похожее, возможно, здесь найдешь полезные идеи.
Выбор шаблона:
Когда я начал работать над блогом, понял, что писать его с нуля — слишком долго. Поэтому решил поискать готовые шаблоны для Next.js. У них есть целый каталог с решениями для блогов, интернет-магазинов, личных страниц и даже сайтов AI-стартапов.
Среди блоговых шаблонов я выбрал тот, который не требует базы данных. Мне хотелось, чтобы сайт был полностью статическим, чтобы его можно было разместить, например, на GitHub Pages, который не поддерживает базы данных.
Моя цель — бесплатный блог без затрат на инфраструктуру. Поэтому я выбрал шаблон с статической генерацией Next.js и Markdown-файлами в качестве источника данных. Такой подход позволяет легко добавлять новые статьи и при этом не платить за сервер.
Установка проекта:
Для начала нужно создать проект с помощью командной строки:
npx create-next-app --example blog-starter blog-starter-app
После этого достаточно заменить статьи из шаблона на свои.
Осталось лишь настроить GitHub Pages для репозитория и привязать CNAME к нужному домену.
Дизайн личной страницы:
Блог был готов, но мне нужна была личная страница, где можно разместить информацию обо мне и моих проектах.
В Figma Community есть множество бесплатных и платных шаблонов, которые можно использовать в своих проектах. Главное — учитывать лицензию. Я искал варианты Free to use, но в итоге просто вдохновился готовыми решениями и создал свой собственный дизайн.
Верстка и реализация:
Для верстки я использовал Next.js и Tailwind CSS.
- Next.js отлично подошел, так как я встроил личную страницу в уже готовый шаблон блога.
- Tailwind CSS выбрал за его удобство: он позволяет быстро стилизовать элементы прямо в коде, без написания отдельных CSS-файлов. Это ускоряет процесс разработки.
Благодаря такому подходу реализация заняла минимум времени.
Вот, например, как выглядит header:
const Header: React.FC<{ opacity?: boolean }> = ({ opacity }) => {
const { asPath, locale } = useRouter();
const { t } = useTranslation();
return (
<>
<header
className={cn(
"sticky top-0 w-full specm:h-[54px] h-[36px] z-10 font-montserrat font-semibold text-[14px] flex items-center border-b border-neutral-200",
opacity ? "bg-[#ffffff99]" : "bg-white"
)}
>
<SpecContainer className="flex justify-between">
<Link href="/" locale={locale} className="font-[arial-black]">
PROGOSLING
</Link>
<div className="flex specm:gap-[40px] gap-[10px]">
<Link
href="/"
locale={locale}
aria-disabled={asPath === "/"}
className="aria-disabled:opacity-50 aria-disabled:pointer-events-none hover:underline"
>
{t("common:header.home")}
</Link>
<Link
href="/blog"
locale={locale}
aria-disabled={asPath === "/blog"}
className="aria-disabled:opacity-50 aria-disabled:pointer-events-none hover:underline"
>
{t("common:header.blog")}
</Link>
<Link locale={locale} href="/#projects" className="hover:underline">
{t("common:header.projects")}
</Link>
</div>
<div className="specm:block hidden" />
</SpecContainer>
</header>
<div className="bg-[#381DDB] font-raleway font-bold text-[12px] text-white">
<SpecContainer className="flex justify-between items-center">
<nav className="flex gap-2 items-center">
{locales.map(({ id, name }, i) => (
<React.Fragment key={id}>
{i > 0 && <span>•</span>}
<Link
href={asPath}
locale={id}
aria-disabled={locale === id}
className="block py-[6px] aria-disabled:opacity-50 aria-disabled:pointer-events-none"
>
{name}
</Link>
</React.Fragment>
))}
</nav>
<ul className="flex specm:gap-2">
{social.map(({ element, id }) => (
<li key={id}>{element}</li>
))}
</ul>
<a href="mailto:[email protected]" className="group">
{email}
</a>
</SpecContainer>
</div>
</>
);
};
А вот так — основная страница:
export default function Index({
allPosts,
postsCount,
}: {
allPosts: Post[];
postsCount: number;
}) {
const { locale } = useRouter();
const { t } = useTranslation();
return (
<Layout
title={t("index-page:meta.title")}
description={t("index-page:meta.description")}
header={<Header />}
>
<div className="mt-[3rem]" />
<Main />
<div className="w-full specl:my-[6.25rem] specm:my-[5rem] my-[40px] border-b border-neutral-200" />
<AboutMe />
<LastProjects />
<Blog allPosts={allPosts} postsCount={postsCount} />
</Layout>
);
}
Итоги:
В итоге получилось:
✅ Блог — работает на статической генерации, без бэкенда и БД.
✅ Личная страница — интегрирована в проект и адаптирована под мой стиль.
✅ Хостинг — полностью бесплатный (GitHub Pages).
Теперь можно добавлять контент и развивать проект дальше.
Если ты тоже хочешь сделать свой сайт, попробуй похожий подход — используй готовые решения и адаптируй их под себя.