ساخت یک وبلاگ داینامیک سمت مشتری با Secutio و Bootstrap

به طور سنتی، ایجاد یک وبلاگ شامل زبان های برنامه نویسی سمت سرور مانند PHP بود. اما اگر بتوانید با جاوا اسکریپت و قدرت رندر سمت کلاینت به همین عملکرد دست پیدا کنید چه؟
اینجاست که چارچوب Secutio وارد میشود. Secutio به شما این امکان را میدهد که محتوای پویا در سمت مشتری بسازید و به شما امکان میدهد با استفاده از قالبهای تحت اللفظی جاوا اسکریپت، یک تجربه وبلاگ کامل ایجاد کنید.
این را تصور کنید: میتوانید یک برنامه وب ایجاد کنید که مانند یک وبسایت سنتی عمل کند و با URLهای پست فردی که سئوساز هستند، کامل شود. این بدان معناست که موتورهای جستجو می توانند به راحتی محتوای وبلاگ شما را کشف و فهرست کنند و دید آنلاین شما را افزایش می دهند.
نگاهی کوتاه بیاندازید! آیا می خواهید قبل از فرو رفتن در جزئیات، پروژه نهایی را ببینید؟
$ git clone https://github.com/mrhdias/secutio
$ cd secutio/examples/blog
$ python3 -m http.server -d public
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
پروژه Secutio نسبتاً جدید است، که با توجه به انبوهی از چارچوبهایی که هدف یکسانی از ارائه ابزارهایی برای ایجاد سریع و آسان وبسایتها را به توسعهدهندگان دارند، چالشی را در جلب توجه توسعهدهندگان و جلب توجه ایجاد میکند. علیرغم این سناریوی رقابتی، من به همسویی پروژه خود با این اهداف اعتقاد دارم، چیزی که ما را به جلو سوق می دهد.
استفاده از بوت استرپ برای افزایش تجربه کاربری
برای نشان دادن موثر قابلیتهای Secutio برای توسعه سریع وب، ما چارچوب محبوب Bootstrap را به عنوان پایه انتخاب کردهایم. بوت استرپ یک رابط کاربری قوی و کاربرپسند ارائه می دهد که آن را به انتخابی ایده آل برای ساخت پایه پروژه تبدیل می کند.
ما بر اساس مفهوم وبلاگ بوت استرپ خواهیم بود، اما با یک نوآوری کلیدی: هر پست وبلاگ زمانی که از صفحه اصلی به آن دسترسی پیدا کنید، در یک پنجره مودال نمایش داده می شود. علاوه بر این، هر پست دارای یک URL اختصاصی است که از دید موتورهای جستجو بهینه برای قابلیت کشف بهتر اطمینان حاصل می کند.
ساده سازی توسعه وب سایت با قالب ها
توسعه یک وبسایت پویا اغلب شامل تکرار محتوا است، چالشی که میتوان با تبدیل آن به قالبهای قابل استفاده مجدد یا اجزای وب، و افزایش ماژولار بودن و کارایی، به طور مؤثر آن را برطرف کرد.
این فرآیند با تجزیه و تحلیل کامل ساختار وب سایت برای شناسایی بخش های تکرارشونده مانند منوهای پیمایش، پست های اخیر یا فهرست های آرشیو آغاز می شود. سپس هر بخش شناسایی شده استخراج شده و به یک الگو یا جزء تبدیل می شود. این قالبها شبیه به ابزارکهای وردپرس عمل میکنند و مدیریت و اصلاح یکپارچه محتوا را تسهیل میکنند.
در این مورد خاص، این فرآیند منجر به ایجاد دوازده الگوی مجزا شد که هر کدام برای عملکردهای خاص طراحی شده بودند. این الگوها به طور یکپارچه در فهرست وب سایت ادغام شدند و انعطاف پذیری کلی و سهولت مدیریت آن را افزایش دادند.
وبلاگ
├── blog/
│ ├── public/
│ │ ├── templates/
│ │ │ ├── top-bar.html
│ │ │ ├── nav-bar.html
│ │ │ ├── featured-post.html
│ │ │ ├── featured-posts.html
│ │ │ ├── panel-posts.html
│ │ │ ├── list-posts.html
│ │ │ ├── panel-archives.html
│ │ │ ├── panel-elsewhere.html
│ │ │ ├── footer.html
│ │ │ ├── btn-scroll-to-top.html
│ │ │ ├── modal-post.html
│ │ │ ├── nav-modal.html
│ │ ├── assets/
│ │ │ ├── css/
│ │ │ │ ├── styles.css
│ │ ├── index.html
│ │ ├── post.html
│ │ ├── tasks.json
│ │ ├── tasks-post.json
└── server.py
در مورد SPA (برنامه تک صفحه ای)، تنها لازم است از یک صفحه HTML به عنوان پایه پروژه استفاده شود. با این حال، در نظر گرفتن این نکته مهم است که بسیاری از پروژههای مبتنی بر SPA به ابزارهای دسترسی جایگزین برای رباتها نیاز دارند تا محتوا را برای اهداف SEO فهرست کنند. بنابراین، ما یک صفحه اضافی به نام “post.html” اضافه می کنیم که برای نمایش محتوای پست در هنگام دسترسی از طریق URL طراحی شده است.
رویدادهای عناصر HTML را با وظایف مرتبط کنید
اصل کار چارچوب Secutio شامل مرتبط کردن وظایف با عناصر برای تولید محتوای پویا است.
وظایف را تعریف کنید
پس از برش هر قطعه از صفحه ‘index.html’ و قرار دادن آنها در قالب ها، گام بعدی این است که وظایفی را به هر عنصر HTML اختصاص دهید که در آن محتوا نمایش داده می شود. سپس این وظایف با الگوی مربوطه مرتبط یا مرتبط می شوند.
کد HTML ارائه شده در زیر با صفحه اصلی وبلاگ Bootstrap مطابقت دارد مثال. در این پروژه، پیوندی به فایل JSON حاوی وظایف (<script data-tasktable type="application/json" src="https://dev.to/mrhdias/tasks.json"></script>
) اضافه شده است. علاوه بر این، آدرس کتابخانه Secutio در انتهای عنصر بدنه HTML گنجانده شده است.
public/index.html
<!doctype html>
<html lang="en" data-bs-theme="auto">
<head>
<!-- missing content -->
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@docsearch/css@3">
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
crossorigin="anonymous">
<!-- Custom styles for this template -->
<link rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Playfair+Display:700,900&display=swap">
<link rel="stylesheet"
href="assets/css/styles.css" rel="stylesheet">
<script data-tasktable type="application/json" src="https://dev.to/mrhdias/tasks.json"></script>
</head>
<body>
<!-- missing content -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/mrhdias/secutio@master/dist/js/secutio.min.js"></script>
</body>
</html>
بعد از عنصر HTML “body”، سرصفحه صفحه را شامل میشود که از یک نوار بالا و یک منو با دستههای مختلف تشکیل شده است.
public/index.html
<!-- missing content -->
<!-- header with topbar and menu with categories -->
<div class="container">
<header id="top-bar"
data-tasks="add-topbar"
class="border-bottom lh-1 py-3"></header>
<div class="py-1 mb-3 border-bottom">
<nav class="navbar navbar-expand-lg">
<div class="container-fluid">
<button class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#large-nav-bar"
aria-controls="large-nav-bar"
aria-expanded="false"
aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div id="large-nav-bar"
data-tasks="add-navbar"
class="collapse navbar-collapse justify-content-center">
</div>
</div>
</nav>
</div>
</div>
<!-- missing content -->
عنصر هدر HTML و عنصر با شناسه “#large-nav-bar” هر دو دارای ویژگی به نام “data-tasks” هستند. این ویژگی شامل نام وظیفه ای است که باید هنگام وقوع یک رویداد مشخص اجرا شود، همانطور که در فایل “https://dev.to/mrhdias/tasks.json” تعریف شده است. در این مورد خاص، رویدادی که مسئول اجرای کار است “init” نامیده می شود. این به طور خودکار پس از بارگیری صفحه HTML آغاز می شود و نیازی به تعامل کاربر ندارد.
public/tasks.json
{
"add-topbar": {
"trigger": "init",
"template": "templates/top-bar.html",
"target": "#top-bar",
"swap": "inner"
},
"add-navbar": {
"trigger": "init",
"src-data": "data/navbar.json",
"template": "templates/nav-bar.html",
"target": "#large-nav-bar",
"swap": "inner"
}
}
تمام خواص در اسناد Secutio مستند شده است. همانطور که در بالا ذکر شد، فقط وظایف با رویداد “init” به طور خودکار در بارگذاری صفحه بارگیری می شوند. با این حال، ویژگی “next” اجازه می دهد تا محتوای اضافی را در همان رویداد بارگیری کنید، همانطور که در قطعه کد زیر که در آن دکمه اسکرول به بالا بارگذاری می شود، مثال می زنیم.
public/tasks.json
{
"add-footer": {
"trigger": "init",
"template": "templates/footer.html",
"target": "footer",
"swap": "inner",
"before": "add-footer-classes",
"next": "add-btn-scroll-to-top"
},
"add-footer-classes": {
"selector": "footer",
"add": {
"class": "py-5 text-center text-body-secondary bg-body-tertiary"
}
},
"add-btn-scroll-to-top": {
"template": "templates/btn-scroll-to-top.html",
"target": "footer",
"swap": "after"
}
}
ویژگی “next” در وظایف به زنجیره زدن چندین کار اجازه می دهد تا به ترتیب مشخص اجرا شوند. به طور مشابه، ویژگی «داده-وظایف» میتواند فهرستی از وظایف جدا شده با فاصله را در خود جای دهد، تا زمانی که این وظایف برای همان رویدادی که خود عنصر در نظر گرفته نشده باشد، امکان اجرای چندین کار را برای یک عنصر فراهم میکند.
سه ویژگی اضافی، «then»، «پیش از این» و «after» به شما این امکان را میدهند که کلاسها و سبکها را در حین مدیریت رویداد اضافه یا حذف کنید. ویژگی “then” بلافاصله پس از شروع رویداد اجرا می شود و برای شروع یک چرخش برای نشان دادن پیشرفت عالی است. ویژگی “before” قبل از به روز رسانی (“swap”) محتوا در عنصر هدف اجرا می شود، در حالی که ویژگی “after” پس از تکمیل به روز رسانی اجرا می شود.
قطعه وظایف ارائه شده استفاده از ویژگی “src-data” را نشان می دهد. این ویژگی منبع داده ایستا را مشخص می کند که می تواند JSON یا فایل متنی باشد. هنگامی که در داخل یک کار اعلان می شود، داده های این منبع توسط وظایف بعدی که توسط برخی رویدادها ایجاد می شوند به ارث می رسند. این وراثت ادامه می یابد مگر اینکه یک ویژگی جدید “src-data” به صراحت برای یک کار خاص تعریف شده باشد یا با ویژگی “ویژگی-src-data” لغو شود.
منابع اطلاعات
این پروژه وبلاگ از داده های ثابت استفاده می کند، به این معنی که محتوا باید از قبل در فایل های JSON آماده و ذخیره شود. در حالی که ایجاد دستی یک گزینه است، توصیه نمی شود. یک رویکرد کارآمدتر استفاده از اسکریپتی است که داده های مربوطه را برای هر پست مستقیماً از پایگاه داده یا باطن دریافت می کند.
در این پروژه، ما رویکرد اسکریپت را انتخاب کرده ایم. همانطور که در تصویر زیر نشان داده شده است، دادههای هر پست در فایلهای JSON جداگانه که در دایرکتوری “data/raw” قرار دارند، ذخیره میشوند:
عمومی/داده/خام
├── blog/
│ ├── bin/
│ │ │── metamorph.py
│ ├── public/
│ │ ├── data/
│ │ │ ├── raw/
│ │ │ │ ├── 1.json
│ │ │ │ ├── 2.json
│ │ │ │ ├── 3.json
│ │ ├── templates/
│ │ ├── assets/
│ │ ├── index.html
│ │ ├── post.html
│ │ ├── tasks.json
│ │ ├── tasks-post.json
└── server.py
به عنوان مثال، ما میتوانیم فایل زیر را با اطلاعات مرتبط برای پر کردن وبلاگ، یا از یک Backend از طریق REST API یا حتی از WordPress REST API ایجاد کنیم. این رویکرد همچنین میتواند برای تولید محتوای چندزبانه ثابت با افزودن دایرکتوریهای اضافی با زبان به فهرست «داده/خام» استفاده شود.
public/data/raw/1.json
{
"id": 1,
"category": "Naturale",
"date_created": "2023-09-30T18:01:14",
"title": "Curabitur volutpat",
"excerpt": "Gravida ligula accumsan cursus. Donec consequat nibh id diam accumsan, eu suscipit ipsum condimentum.",
"text": "Maecenas lacinia est hendrerit lobortis suscipit. Curabitur purus neque, dignissim vel lacinia eleifend, pellentesque imperdiet augue. Suspendisse vestibulum rutrum nibh, in facilisis urna pharetra at. Integer posuere nunc eu justo ultrices semper. Aliquam ut ullamcorper purus, et malesuada dui. Fusce nec lorem ultrices, malesuada ipsum a, feugiat dui. Donec tortor nulla, sagittis et erat a, finibus dapibus libero.",
"image": {
"src": "uploads/woman-tearing-mint-leaves.jpg",
"name": "",
"alt": ""
},
"permalink": "post.html?id=1",
"author": "Aliquam Tincidunt",
"views": 5,
"featured": true
}
با استفاده از یک اسکریپت پایتون به نام “metamorph.py” که در فهرست “bin” مخزن قرار دارد، می توان انواع مختلفی از فایل های JSON را برای مصرف توسط الگوها تولید کرد. فیلمنامه را می توان در اینجا به تفصیل تحلیل کرد.
پس از اجرای اسکریپت “metamorph.py”، داده ها و ساختار فهرست فایل به صورت زیر است:
├── blog/
│ ├── bin/
│ │ │── metamorph.py
│ ├── public/
│ │ ├── data/
│ │ │ ├── archives/
│ │ │ │ ├── 2023-09/
│ │ │ │ │ ├── 1.json
│ │ │ │ ├── 2024-02/
│ │ │ │ ├── 2024-04/
│ │ │ ├── categories/
│ │ │ │ ├── all/
│ │ │ │ │ ├── 1.json
│ │ │ │ ├── imaginatio/
│ │ │ │ ├── mundos/
│ │ │ ├── posts/
│ │ │ │ ├── 1.json
│ │ │ │ ├── 2.json
│ │ │ │ ├── 3.json
│ │ │ ├── raw/
│ │ │ │ ├── 1.json
│ │ │ │ ├── 2.json
│ │ │ │ ├── 3.json
│ │ │ ├── archives.json
│ │ │ ├── elsewhere.json
│ │ │ ├── featured-post.json
│ │ │ ├── featured-posts.json
│ │ │ ├── most-read.json
│ │ │ ├── navbar.json
│ │ │ ├── recent-posts.json
│ │ ├── templates/
│ │ ├── assets/
│ │ ├── index.html
│ │ ├── post.html
│ │ ├── tasks.json
│ │ ├── tasks-post.json
└── server.py
محتویات ساختار دایرکتوری را می توان با جزئیات در مخزن که وبلاگ نمونه در آن قرار دارد مشاهده کرد.
در زیر فایل JSON مورد استفاده برای پر کردن قالب نوار منو است.
public/data/navbar.json
[
{
"category": "Most Recent",
"category_slug": "all",
"page": 1
},
{
"category": "Imaginatio",
"category_slug": "imaginatio",
"page": 1
},
{
"category": "Mundos",
"category_slug": "mundos",
"page": 1
}
]
پر کردن قالب ها با داده ها
اکنون بیایید الگوها و نحوه ارتباط داده ها با آنها را بررسی کنیم. ما الگوی مورد استفاده برای تولید منوی پیمایش را که توسط کار “add-navbar” راه اندازی شده است، بررسی خواهیم کرد:
public/templates/nav-bar.html
<ul class="navbar-nav nav-underline">${(() => {
if (!task.ok) {
return task.status === 404 ? `<strong>${data}</strong>` : 'an error happened!';
}
return data.map(record => `<li class="nav-item">
<a href="/?page=1&category-slug=${record.category_slug}#posts-list"
${window.location.pathname !== '/post.html' ?
`data-tasks="show-posts-list"
data-trigger="click"
data-after="remove-active-menu add-active-menu scroll-into-posts-list"
data-src-data="data/categories/${record.category_slug}/1.json"` : ''}
class="nav-item nav-link ${window.location.pathname !== '/post.html' &&
record.category_slug === 'all' ? 'active' : ''}">${record.category}</a>
</li>`).join("");
})()}</ul>
قالب ترکیبی از HTML و جاوا اسکریپت است. برای درک این رویکرد، نحوه تولید صفحات PHP را در نظر بگیرید. در PHP، کد در HTML جاسازی شده است. به طور مشابه، این کتابخانه از الگوهای جاوا اسکریپت برای رسیدن به همان هدف استفاده می کند. از این تعریف: “الفظ الگو، حروفی هستند که با کاراکترهای بک تیک (`) محدود شده اند، که امکان رشته های چند خطی، درونیابی رشته ای با عبارات تعبیه شده و ساختارهای خاصی به نام الگوهای برچسب گذاری شده را فراهم می کند.”
در این مثال، یک شی به نام “تکلیف” و یک متغیر به نام “داده” را می بینیم. در اصل، متغیر “داده” به عنوان میانبر برای “task.result” عمل می کند. ویژگی های “ok” و “وضعیت” در شی “وظیفه” نتیجه کار را نشان می دهد و با نتیجه واکشی داده مطابقت دارد. بعلاوه، شیء “تکلیف” حاوی شی “رویداد” است که از طریق ویژگی “رویداد” قابل دسترسی است: “task.event”.
علاوه بر این، الگوها را می توان از طریق عنصر HTML “الگو” در کد HTML گنجانید یا از طریق ویژگی “is-template” در سمت سرور منتقل شد، که به کار اضافه شده یا در ” مشخص شده است.Secutio-Transformation: is-template:true
” header. در این سناریو، ویژگی template به شی “task” اضافه می شود و از طریق “task.template” دسترسی به الگو را فراهم می کند.
public/tasks.json
{
"show-posts-list": {
"trigger": "init",
"attribute-trigger": "data-trigger",
"src-data": "data/categories/all/1.json",
"attribute-src-data": "data-src-data",
"template": "templates/list-posts.html",
"target": "#posts-list",
"swap": "inner",
"after": "scroll-into-posts-list",
"attribute-after": "data-after"
}
}
همانطور که در قالب ارائه شده مشاهده می شود، وظیفه “show-posts-list” به طور خودکار پس از بارگیری وبلاگ شروع می شود. این کار آخرین پست ها را نمایش می دهد. با این حال، زمانی که کاربر برای دسترسی به پستها از طریق رویداد کلیک روی لیست کلیک میکند، مکانیسم راهاندازی کمی متفاوت است.
در اینجا یک تفکیک از روند است:
- عنصر HTML که در آن وظیفه اعلان می شود دارای یک ویژگی به نام “data-trigger” است.
- هنگامی که یک رویداد کلیک لیست را بارگذاری می کند، مقدار ویژگی “data-trigger” جایگزین ویژگی “trigger” در اعلان وظیفه می شود.
- این جایگزینی همچنین برای ویژگی های “src-data” و “after” وظیفه اعمال می شود.
اگر استفاده مجدد از یک کار موجود مورد نظر نیست، یک کار جدید همیشه می تواند به طور خاص برای رویداد کلیک اعلام شود.
نحوه رفع مشکلات سئو در برنامه های وب تک صفحه ای (SPA)
برای بهبود بهینهسازی موتور جستجو (SEO) برای یک اپلیکیشن تک صفحهای (SPA)، توسعهدهندگان میتوانند از نقشههای سایت استفاده کنند و به ایجاد صفحات جداگانه فکر کنند. این به موتورهای جستجو اجازه می دهد تا پیوندها را دنبال کنند و به طور بالقوه فهرست بندی محتوا را در SPA بهبود بخشند.
در SPA ها، روش “replaceState()” رابط History برای به روز رسانی URL زمانی که کاربران به محتوای خاصی هدایت می شوند استفاده می شود. این روش ورودی تاریخچه فعلی را تغییر می دهد و آن را با یک شیء حالت و یک URL که محتوای نمایش داده شده را منعکس می کند جایگزین می کند.
public/templates/single-post.html
${(() => {
if (!task.ok) {
return task.status === 404 ?
`<strong>${data}</strong>` : 'an error happened!';
}
history.replaceState({}, "", data.permalink);
return `<h3 class="pb-4 mb-4 fst-italic border-bottom">From the ${data.category}</h3>
<article class="blog-post">
<h2 class="display-6 link-body-emphasis mb-1">${(() => {
document.title="Large - " + data.title;
return data.title;
})()}</h2>
<p class="blog-post-meta">${(() => {
const dc = new Date(data.date_created + 'Z');
return dc.toLocaleString('en-us',{year:'numeric', month:'long', day:'numeric'});
})()} by <a href="#">${data.author}</a>
</p>
<p>
<img src="${data.image.src}"
class="figure-img img-thumbnail rounded"
alt="${data.image.alt}"
style="width: 50%;float: left;margin-right: 20px;">
${data.text}
</p>
</article>`;
})()}
همانطور که از الگوی بالا مشخص است، هر زمان که کاربر به یک پست دسترسی پیدا می کند، URL مشتری به URL مشخص شده در منبع داده برای آن پست (“data.permalink”) تغییر می کند. همین رفتار هنگام پیمایش به یک دسته از منو اتفاق میافتد، پس از آن فهرست مقالات موجود در آن دسته نمایش داده میشود (public/templates/list-posts.html).
پیش نمایش زنده
این مثال از هیچ پایگاه داده ای استفاده نمی کند. این بر اساس فایل های ثابت است و فقط به یک سرور HTTP برای اجرا نیاز دارد. هرگونه تغییر دستی در فایلهای JSON در فهرست دادههای “data/raw” نیازمند اجرای اسکریپت “metamorph.py” برای بهروزرسانی فایلهای باقیمانده است.
برای مشاهده وبلاگ کافی است از سرور HTTP پایتون استفاده کنید و دستور زیر را اجرا کنید:
$ cd blog
$ python3 -m http.server -d public
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
نتیجه
در این پروژه، هدف ما نشان دادن اثربخشی ادغام چارچوب Secutio با Bootstrap برای سادهسازی توسعه برنامههای کاربردی وب پویا بود. در مقایسه با استفاده از قالب های PHP در توسعه وب سایت، رویکرد وظیفه محور Secutio با قالب های تحت اللفظی جاوا اسکریپت نیاز به جاوا اسکریپت گسترده را هنگام کار با مؤلفه های Bootstrap به حداقل می رساند. این روش پتانسیل این را دارد که زمان و پیچیدگی توسعه را به میزان قابل توجهی کاهش دهد و آن را برای ساخت برنامه های کاربردی وب تعاملی و پاسخگو مناسب کند.
کد منبع این پروژه در اینجا موجود است.
جزئیات و توضیحات اضافی در اسناد چارچوب موجود است. از اینجا هم می توانید به کد دسترسی پیدا کنید.
با تشکر از شما برای خواندن!