ساخت این وبلاگ، بدون ساختن یک CMS
· 6 دقیقه مطالعهمهندسی #typescript #static-site #web-development
این وبلاگ با یک ایدهی ساده شروع شد: میخواستم جایی داشته باشم که به انگلیسی و فارسی بنویسم، چند پروژه را نشان بدهم و برای اداره کردنش به CMS نیاز نداشته باشم.
این تصمیم خیلی از ابزارها را از همان ابتدا کنار میگذارد. نه پایگاهدادهای داریم، نه نیاز به فریم ورک خاص و یا Api سرور. مرجع اصلی ریپازیتوری کد است. محتوا در فایلها قرار میگیرد، فرایند build با Node.js و TypeScript آنها را به HTML استاتیک تبدیل میکند و این همان چیزی است که منتشر میشود.
این مدل برای این سایت مناسب است، چون محتوا را یک نفر ویرایش میکند، ساختار ساده است و انتشار باید بدون دردسر و مشکل باشد.
ساختار پروژه
ساختار پروژه تقریباً اینطور است:
Blog/
├── posts/
│ ├── en/
│ │ └── building-this-blog/
│ │ └── index.md
│ └── fa/
│ └── building-this-blog/
│ └── index.md
├── pages/
│ ├── en/
│ │ └── about.html
│ └── fa/
│ └── about.html
├── src/
│ └── templates/
└── public/
محتوا در فایلها میماند
نوشتهها و پروژهها ساختار یکسانی دارند:
posts/en/<slug>/index.md
posts/fa/<slug>/index.md
projects/en/<slug>/index.md
projects/fa/<slug>/index.md
هر فایل Markdown با یک بخش front matter شروع میشود. build از این بخش برای عنوان، خلاصه، تاریخ، وضعیت انتشار، دستهبندیها، برچسبها و پیوند ترجمه استفاده میکند.
---
title: ساخت این وبلاگ، بدون ساختن یک CMS
summary: توضیح کوتاه برای صفحههای فهرست.
language: fa
date: 2026-08-12
published: false
categories: [engineering]
tags: [typescript, static-site]
translationOf: building-this-blog
---
translationOf نوشتههای انگلیسی و فارسی را با یک مقدار مشترک به هم وصل میکند. وقتی خواننده در صفحهی یک نوشته یا پروژه زبان را عوض میکند، سایت میتواند کاربر را به صفحهی درست هدایت کند.
صفحههای مستقلی مثل About و Contact حتی سادهترند: چند قطعهی HTML قابل ویرایش در pages/en/ و pages/fa/. build پوستهی سند، ناوبری و فوتر را به آنها اضافه میکند.
build چه تولید میکند
build پوشههای محتوا را میخواند، front matter اجباری را بررسی میکند و برای نوشتهها و پروژههای منتشرشده صفحه میسازد. صفحهی اصلی هر زبان، صفحههای جزئیات نوشته و پروژه، فهرست پروژهها، فهرست دستهبندی و برچسب، صفحههای مستقل، robots.txt، sitemap و صفحهی 404 هم تولید میشوند.
خروجی، HTML استاتیک معمولی است؛ بنابراین Node.js لازم نیست روی سرور اجرا شود. هر میزبانی که فایلهای استاتیک را پشتیبانی کند، میتواند سایت را منتشر کند.
build را عمداً محدود نگه داشتهام.این پروژه قرار نیست به یک پلتفرم انتشار همهمنظوره تبدیل شود. جستوجو، کامنت، حساب کاربری یا چندنویسنده داشتن دلایل خوبی هستند تا معماری را دوباره بررسی کنم.
قالبهای قابل ویرایش، چیدمان مشترک
پوستهی مشترک صفحه، HTML سادهای در src/templates/ است و از جاینگهدارهای کوچکی مثل {{title}}، {{content}} و {{navigation}} استفاده میکند.
TypeScript بخشهای تکراری را میسازد، محتوای غیرقابلاعتماد را ایمنسازی میکند و نتیجه را در قالبها قرار میدهد. اگر قالبها به حلقه، شرط یا وراثت نیاز داشتند، یک زبان قالب کامل مفید بود. این سایت به آنها نیاز ندارد.
همین روش هر دو زبان را بدون تکرار چیدمان پوشش میدهد. انگلیسی با نشانهگذاری چپچین و فارسی با نشانهگذاری راستچین و فونت Vazir نمایش داده میشود. زبانگزین هم هرجا صفحهی معادل وجود داشته باشد حتی در فهرست پروژهها و صفحههای مستقلی مثل درباره من و تماس مسیر فعلی را حفظ میکند.
Markdown و رفتار مرورگر
محتوای سایت با Markdown نوشته میشود و برای قابلیتهایی مثل جدول، فهرست وظایف، خطخوردگی، لینک خودکار و بلوک کد از GitHub Flavored Markdown1 استفاده میکند.
HTML خام داخل Markdown ایمنسازی میشود و بهجای رندر شدن، بهصورت متن باقی میماند. Markdown برای محتوای مقاله و قالبهای HTML مشترک برای ساختار سایت استفاده میشود. این مرز قالب محتوا را قابلپیشبینی نگه میدارد و نمیگذارد markup دلخواه داخل یک نوشته بیسروصدا صفحه را تغییر دهد.
این سایت برای کارهای لازم، مقدار کمی جاوااسکریپت استفاده میکند:
- دکمهی تغییر تم انتخاب کاربر را در
localStorageنگه میدارد و اگر انتخابی وجود نداشته باشد، از تنظیمات سیستم پیروی میکند. - زبانگزین زبانی را که خواننده انتخاب کرده به یاد میسپارد.
- لینک ایمیل تماس در مرورگر و از چند attribute جداگانه ساخته میشود. این کار جمعآوری سادهی آدرس ایمیل را سختتر میکند، اما اگر اسپم به مشکل تبدیل شود، جای فرم تماس واقعی را نمیگیرد.
منوی دستهبندی یک عنصر native به نام <details> است و به JavaScript نیاز ندارد.
بررسیها پیش از انتشار
یک سایت محتوامحور هم میتواند خراب شود. نبودن فیلدهای اجباری، تاریخ نامعتبر، ناهماهنگی زبان یا جاینگهدار حلنشدهی قالب میتواند صفحهی خراب تولید کند.
مجموعهی تست، اعتبارسنجی front matter، پیوندهای دوزبانه، پروژههای پینشده در صفحهی اصلی، assetهای استاتیک، قالبها، زبانگزینی با حفظ مسیر و رندر GFM را بررسی میکند. پیش از انتشار این دستورها را اجرا میکنم:
npm test
npm run lint
npm run build
npm run build پوشهی dist/ را پاک و دوباره ایجاد میکند، سپس assetهای عمومی و فایلهایی را که باید کنار یک نوشته یا پروژه قرار بگیرند کپی میکند. خروجی تولیدشده موقتی است؛ فایلهای منبع اهمیت دارند.
انتشار هم یک چکلیست کوتاه دارد:
- دستورهای اعتبارسنجی را روی سیستم خود اجرا کنید.
- سایت را build کنید و مطمئن شوید
dist/صفحههای مورد انتظار را دارد. - یک میزبانی استاتیک را طوری تنظیم کنید که
dist/را بهعنوان پوشهی انتشار سرو کند. - دامنه را به آن میزبانی وصل کنید و آدرس اصلی سایت را که build استفاده میکند تنظیم کنید.
- بگذارید CI همین بررسیها را برای pushها یا tagهای انتشار اجرا کند.
میزبانی بخش مهم طراحی نیست. برای انتشار فقط فایلهای استاتیک لازماند. همین موضوع سایت را قابلانتقال نگه میدارد و اجازه میدهد بدون بازنویسی وبلاگ، میزبان را عوض کنم.