
فهرست
مقدمه
صفحه ۱دانلود و نمایش دمو
نصب و اجرا
ویرایش و توسعه
جزییات نصب و اجرا ـ ۱
صفحه ۲عملیات Build
Start پروژه
جزییات نصب و اجرا ـ ۲
صفحه ۳استفاده از Node Stream
آمادهسازی Router
ارتباط با API
صفحه ۴تابع FetchData و پارامترهای آن
تابع API و پارامترهای آن
ارتباط کامپوننتهای React با دادههای API
صفحه ۵پیادهسازی Loading
صفحه ۶پیادهسازی تگهای سرصفحه
صفحه ۷پیادهسازی نقشهی سایت XML
صفحه ۸
در صفحههای قبلی، نحوهی دریافت، نصب و اجرا ، توسعهی پروژه، جزییات نصب و اجرای پروژه، ارتباط با API، نحوهی ارتباط کامپوننتهای React با دادههای دریافتی از API و همچنین نحوهی پیادهسازی Loading، توضیح داده شد. در این صفحه به سراغ نحوهی پیادهسازی تگهای سرصفحه، میرویم.
پیادهسازی تگهای سرصفحه
در این پروژه، برای گنجاندن متاتگها و همچنین تگهای موردنظرِ دیگر در سرصفحهی صفحههای مختلف، از پکیج react-helmet استفاده شده که از رندرینگ سمت سرور نیز پشتیبانی میکند.
React Helmet در کامپوننتی به نام <MetaTags />
در مسیر src/MetaTags.jsx فراخوانی شده و propsهایی دارد که مقادیری که میگیرد را، در درون تگهای مورد نظر، استفاده خواهد کرد.
مثلا در کامپوننت Category که قرار است محتویات یک دستهبندی را نشان دهد، نحوهی بهکارگیری کامپوننت <MetaTags />
، به شکل زیر خواهد بود:
// src/Pages/Category.jsx
import { useState } from "react";import { useParams } from "react-router-dom";
import MetaTags from "../MetaTags";
.
.
const Category = ({ dataFromServer }) => {
const [data, setData] = useState(dataFromServer['firstData']);
.
.
const params = useParams();
const name = params?.name;
.
.
return (
<>
<MetaTags
url={`https://mywebsite.com/category/${name}`}
title={`${name} - Category - MyWebSite`}
description={data?.description || `This is home page of ${name}`}
image={data?.image || `https://mywebsite.com/images/icon.svg`}
/>
<div>...
...
حالا کامپوننت <MetaTags />
، تگ <Helmet>
و محتویات درون آن را برمیگرداند؛ و React Helmet هنگام اجرای صفحه در سمت کلاینت، این محتویات را در Head صفحه میگنجاند.
import { Helmet } from "react-helmet"
const MetaTags = ({ url = '', title = '', robots = 'index, follow', description = '', image = '' }) => {
return (
<Helmet>
<title>{title}</title>
{url && <link rel="canonical" href={url} />}
<meta name="robots" content={robots} />
<meta name="description" content={description} />
.
.
</Helmet>
)
}
export default MetaTags;
پس از نوشتن تگهای سرصفحه در کامپوننتهایِ مورد نظرِ React در درون <Helmet>...</Helmet>
، که به خودی خود در سمت کلاینت رندر میشوند، باید بتوانیم آنها را در سورس HTML سمت سرور نیز قرار دهیم. برای اینکار کافی است پکیج react-helmet را در سمت سرور نیز import کنیم و متد renderStatic()
را در پکیچ import شده، فراخوانی کنیم.
import { Helmet } from "react-helmet";
const helmet = Helmet.renderStatic();
حالا به تگهای مختلفی که در <Helmet>...</Helmet>
کامپوننتهای React مشخص کرده بودیم، دسترسی خواهیم داشت که باید آنها را که هر کدام یک آبجکت هستند، با متد toString()
به رشته تبدیل کنیم.
import { Helmet } from "react-helmet";
const helmet = Helmet.renderStatic();
const header = `<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
${helmet?.title ? helmet?.title?.toString() : ''}
${helmet?.meta ? helmet?.meta?.toString() : ''}
${helmet?.link ? helmet?.link?.toString() : ''}`;
.
.
همانطور که در خطهای ۷ ،۶ و ۸ کد بالا میبینید، تعیین کردهایم که در صورتی که تگ <title></title>
، تگهای <link />
و تگهای <meta />
وجود داشته باشند، درون محتوای ثابت header
قرار بگیرند.
ثابت header
حالا آمادهی جایگذاری در HTML سمت سرور ما خواهد بود. برای اینکار تنها کافیاست در تابع render
فایل server.mjs، محتویات ثابت header
را به جای خط کامنت <!--app-head-->
که در فایل /dist/client/index.html
وجود دارد، قرار دهیم تا محتویات index.html
را برای عملیات رندرینگ تابع render
آماده کرده باشیم. (خط۲۴ کد زیر)
// server.mjs
.
.
import { Helmet } from "react-helmet";
const helmet = Helmet.renderStatic();
const header = `<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
${helmet?.title ? helmet?.title?.toString() : ''}
${helmet?.meta ? helmet?.meta?.toString() : ''}
${helmet?.link ? helmet?.link?.toString() : ''}`;
.
.
const templateIndex = await fs.readFile(`./dist/client/index.html`, 'utf-8');
let template = templateIndex;
const render = (await import(`./dist/server/entry-server.js`)).render;
.
.
app.get('*', async (req, res) => {
const { pipe, abort } = render(path, dataFromServer, {
.
.
template = template.replace('<!--app-head-->', header);
//Ex.
res.write(template);
.
.
}
.
.
کدهای مخصوص Helmet که در خطهای ۴ تا ۱۱ کد بالا نیز مشاهده میشوند، در این پروژه برای دسترسی بهتر و طولانی نشدن کدهای فایل server.mjs، درون یک تابعی دیگری به نام Head
در مسیر core/Head.mjs قرار گرفتهاند. این تابع تگهای مشخص شده را برمیگرداند تا در تابع render
فایل server.mjs استفاده شوند.
تابع Head
یک پارامتر با عنوان baseUrl
دارد که این پارامتر، قرار است در تگ base
به شکل <base href="${baseUrl}" />
به کار گرفته شود.
ثابت WEBSITE_DIRECTORY_NAME
تعریف شده در فایل .env
که در این پروژه shop
تعریف شده است، به عنوان یک آرگومان به شکل /shop/
به پارامتر baseUrl
تابع Head
تعلق خواهد گرفت.
در صورت خالی بودن WEBSITE_DIRECTORY_NAME
، یک /
به عنوان baseUrl
در نظر گرفته خواهد شد.
import Head from './Head.mjs';
import { getEnv } from './Utils.mjs';
.
.
template = template.replace('<!--app-head-->', Head(getEnv('WEBSITE_DIRECTORY_NAME') ? ('/' + getEnv('WEBSITE_DIRECTORY_NAME') + '/') : '/');
.
.
تابع
getEnv
که در کد بالا مشاهده میشود در مسیر core/Utils.mjs قرار دارد و کلید ثابتهای تعریف شده در فایل.env
را میگیرد و مقادیر آنها را برمیگرداند. این تابع از دو پکیج نودجیاس dotenv و dotenv-expand استفاده میکند.
صفحهی قبل: پیادهسازی Loading
صفحهی بعد: پیادهسازی نقشهی سایت XML
اطلاعات برنامه
نام: express-react-ssr
پلتفرم: Node.js
زبان: JavaScript
لایسنس: MIT
تاریخ انتشار اولیه: ۹ مرداد ۱۴۰۳
تاریخ آخرین بهروزرسانی: ۱۱ شهریور ۱۴۰۳
مخزن: GitHub