فعالسازی رندرینگ سمت سرور برای React App
در این مقاله میخوانید
فعالسازی رندرینگ سمت سرور برای React App یکی از تکنیکهای محبوب رندرکردن وب اپلیکیشنهای تکصفحهای (یعنی SPA) است. در فرایند یادشده، صفحه مدنظر پس از رندرینگ کامل به کاربر ارسال میشود. در این روش، کامپوننتهای داینامیک را هم در قالب کدهای HTML استاتیک میتوانیم ارائه دهیم. در مقاله حاضر، نحوه رندرینگ سمت سرور برای React App را گامبهگام آموزش میدهیم.
آموزش فعالسازی Server-Side Rendering یا SSR
سازوکار کلی فعالسازی رندرینگ سمت سرور برای React App بدینترتیب است که ابتدا اپلیکیشن React را بهکمک دستور create-react-app مقداردهی اولیه میکنیم. سپس، تغییراتی ساده را روی پروژه پیاده میکنیم تا رندر سمت سرور را برایش فعال کنیم. در انتها نیز، پروژهای فعال خواهیم داشت که با اپلیکیشن React سمت کلاینت و با اپلیکیشن Express سمت سرور کار میکند.
نکته: قبل از شروع این مراحل، باید Node.js را بهصورت لوکال نصب کرده باشید. درضمن، باید اشاره کنیم که این مراحل برای نسخههای زیر آزمایش و تأیید شدهاند:
- Node v16.13.1
- npm v8.1.2
- react v17.0.2
- babel/core v7.16.0@
- webpack v4.44.2
- express v4.17.1
- nodemon v2.0.15
- npm-run-all v4.1.5
با فعالسازی رندرینگ سمت سرور برای React App امکان رندرگیری از برنامههای تکصفحهای فراهم میشود. با انجام رندرینگ سمت سرور صفحه مورد نظر پس از تکمیل فرایند بهطور کامل بارگذاری شده و به کاربر ارسال میشود. شما میتوانید باتوجهبه سادگی و پیچیدگی برنامههایتان تنظیمات مختلفی را برای رندرینگ سمت سرور با اپلیکیشنهای ریایکت انجام دهید.
مرحله 1. ساخت اپلیکیشن React
بهعنوان اولین قدم بهمنظور رندرینگ سمت سرور برای React App، از npx برای راهاندازی اپلیکیشن جدید React (بهکمک جدیدترین نسخه Create React App) استفاده میکنیم. اینجا اپلیکیشنی را فراخوانی میکنیم که نامش را react-ssr-example گذاشتهایم:
npx create-react-app react-ssr-example
سپس، cd را وارد دایرکتوری جدید میکنیم:
cd react-ssr-example
درنهایت، این اپلیکیشن جدید سمت کاربر را راهاندازی میکنیم تا فرایند نصب آن تأیید شود:
npm start
با این کار، نمونهای از اپلیکیشن React را میبینید که در مرورگرتان باز میشود.
برای راهنمای کامل آموزش پیادهسازی Hook در React مقالهی زیر را بخوانید.
مرحله 2. اصلاح کامپوننتهای برنامه
حالا کامپوننت جدید <Home> را در پوشه src ایجاد میکنیم:
nano src/Home.js
درادامه، کد زیر را به فایل Home.js اضافه میکنیم:
function Home(props) { return <h1>Hello {props.name}!</h1>; }; export default Home;
با این کار، هدینگ <h1> ایجاد میشود که پیام Hello را همراه با نامی خاص نشان میدهد. حالا باید <Home> را در کامپوننت <App> رندر کنیم؛ پس فایل App.js را در پوشه src باز میکنیم:
nano src/App.js
بعدازآن، کدهای جدید زیر را جایگزین کدهای موجود میکنیم:
import Home from './Home'; function App() { return <Home name="Sammy"/>; } export default App;
این کدها نامی (اینجا Sammy) را به کامپوننت <Home> میدهند؛ بنابراین، چنین پیامی نمایش داده خواهد شد:
Output "Hello Sammy!"
در قدم بعدی، در فایل index.js اپلیکیشن از روش ReactDOM’s hydrate بهجای رندر استفاده میکنیم تا به رندرِر DOM نشان دهیم که میخواهیم اپلیکیشن را بعد از رندر سمت سرور، rehydrate کنیم. پس فایل index.js موجود در پوشه src را باز میکنیم:
nano src/index.js
سپس، کدهای زیر را جایگزین محتویات این فایل میکنیم:
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; ReactDOM.hydrate( <React.StrictMode> <App /> </React.StrictMode>, document.getElementById('root') );
با این کار، تنظیمات سمت کلاینت راهاندازی میشود و میتوانیم بهسراغ راهاندازی سمت سرور برویم.
مرحله 3. ایجاد سرور Express
حالا بهمنظور ادامه فعالسازی رندرینگ سمت سرور برای React، باید سروری را برایش راهاندازی کنیم تا نسخه رندرشده را ارسال کند. برای این کار، از Express برای سرور استفاده میکنیم.
توجه: پکیج react-scripts که متعلق به Create-react-app است، نسخهای از Express را بهعنوان پیشنیاز webpack-dev-server نصب میکند. در این آموزش، از این مرحله عبور میکنیم.
پوشه سرور جدیدی در پوشه روت پروژه میسازیم:
mkdir server
پسازآن در پوشه سرور، فایل index.js جدیدی میسازیم که حاوی کدهای سرور Express است:
nano server/index.js
حالا چند ثابت را تعریف و ایمپورتهای لازم را اضافه میکنیم:
import path from 'path'; import fs from 'fs'; import React from 'react'; import ReactDOMServer from 'react-dom/server'; import express from 'express'; import App from '../src/App'; const PORT = process.env.PORT || 3006; const app = express();
مرحله 4. رندرکردن کامپوننتهای اپلیکیشن
در قدم بعدی، کدهای زیر را برای مدیریت خطاها به کدهای سرور اضافه میکنیم:
// ... app.get('/', (req, res) => { const app = ReactDOMServer.renderToString(<App />); const indexFile = path.resolve('./build/index.html'); fs.readFile(indexFile, 'utf8', (err, data) => { if (err) { console.error('Something went wrong:', err); return res.status(500).send('Oops, better luck next time!'); } return res.send( data.replace('<div id="root"></div>', `<div id="root">${app}</div>`) ); }); }); app.use(express.static('./build')); app.listen(PORT, () => { console.log(`Server is listening on port ${PORT}`); });
شایان ذکر است که امکان واردکردن کامپوننت <App> از پوشه client-app از سرور وجود دارد.
در کدهای بالا سه اتفاق رخ میدهد:
- از Express برای ارائه محتویات از پوشه build بهعنوان فایلهای استاتیک استفاده میشود.
- از renderToString که مربوط به ReactDOMServer است، برای رندرگرفتن از اپلیکیشن بهعنوان استرینگ HTML استاتیک استفاده میشود.
- فایل استاتیک index.html از کلاینت اَپلیکیشن build خوانده میشود. سپس، محتواهای استاتیک اپلیکیشن با یک id به نام root به <div> تزریق میشوند (این بهعنوان پاسخ به درخواست ارسال میشود).
مرحله 5. پیکربندی Webpack و Babel
در این مرحله از رندرینگ سمت سرور برای React App، باید کدهای سرور را با استفاده از Webpack و Babel باندل و ترنسپایل کنیم تا این کدهای سرور کار کنند.
توجه: برای ادامه مراحل، باید babel-core و babel-preset-env و babel-preset-react-app را نصب کرده باشید. این پکیجها از همان زمان نصب آرشیو و نسخه monorepo بهجای آنها استفاده میشوند.
درضمن، react-scripts متعلق به Create-react-app نصب این پکیجها را مدیریت میکند: webpack ،webpack ،webpack-node-externals ،babel/core@ ،babel-loader babel/preset-env@ و babel/preset-react@. بنابراین، از آموزش این مرحله عبور میکنیم و بهسراغ ادامه مراحل میرویم.
حالا فایل پیکربندی جدید Babel را در پوشه روت پروژه میسازیم:
nano .babelrc.json
بعد پریستهای env و react-app را اضافه میکنیم:
{ "presets": [ "@babel/preset-env", "@babel/preset-react" ] }
نکته: قبلاً از فایل babelrc. (بدون پسوند json.) استفاده میشد؛ اما این روش فقط در Babel 6 پاسخگو بود و دیگر در Babel 7 استفاده نمیشود.
در گام بعدی، webpack config برای سرور ایجاد میکنیم که از Babel Loader برای ترانسپایلکردن کدها استفاده میکند. برای شروع، فایل webpack.server.js را در پوشه روت پروژه میسازیم:
nano webpack.server.js
سپس، تنظیمات زیر را به فایل webpack.server.js اضافه میکنیم:
const path = require('path'); const nodeExternals = require('webpack-node-externals'); module.exports = { entry: './server/index.js', target: 'node', externals: [nodeExternals()], output: { path: path.resolve('server-build'), filename: 'index.js' }, module: { rules: [ { test: /\.js$/, use: 'babel-loader' } ] } };
با این پیکربندی باندل سرور که ترنسپایل شده است، در پوشه server-build و در فایلی به نام index.js خروجی گرفته میشود. استفاده از ‘target: ‘node و externals: [nodeExternals()] از webpack-node-externals نیز که فایلهای node_modules را حذف میکند، بخش مهم این فرایند است (سرور میتواند مستقیماً به این فایل دسترسی داشته باشد).
مرحله 6. پیکربندی اسکریپتهای npm
فایل package.json را دوباره ویرایش و اسکریپتهای کمکی npm زیر را به آن اضافه میکنیم:
nano package.json
سپس، dev:build-server و dev:start و dev scripts را به فایل package.json اضافه میکنیم تا اپلیکیشن SSR را بسازیم:
"scripts": { "dev:build-server": "NODE_ENV=development webpack --config webpack.server.js --mode=development -w", "dev:start": "nodemon ./server-build/index.js", "dev": "npm-run-all --parallel build dev:*", // ... },
اسکریپت dev:build-server محیطی برای development فراهم و webpack را با فایل پیکربندیای فراخوانی میکند که قبلاً ساختهایم. اسکریپت dev نیز npm-run-all را فراخوانی میکند تا کدهای build و همه کدهایی که با *dev: شروع میشوند (شامل dev:build-server و dev:start)، در parallel اجرا کند. از nodemon نیز برای ریاستارتکردن سرور بعد از اعمال تغییرات استفاده میشود.
توجه: به تغییر اسکریپتهای start ،build ،test و eject که ازقبل در فایل package.json موجودند، نیازی نیست.
حالا دستورهای زیر را در پنجره ترمینال وارد میکنیم تا این پکیجها نصب شوند:
npm install [email protected] --save-dev npm install [email protected] --save-dev
با این کار، میتوانیم کد زیر را اجرا کنیم تا باندل اپلیکیشن سمت کاربر ساخته شود و کدهای سرور ترانسپایل شوند و سرور در 3006: اجرا شود.
npm run dev
حالا تنظیمات server webpack به تغییرات پی میبرد و سرور ریاستارت میشود. بااینحال، اپلیکیشن کلاینت هربار بعد از تغییرات باید بهصورت دستی بازسازی شود.
بهعنوان مراحل نهایی فعالسازی رندرینگ سمت سرور برای React App، آدرس /http://localhost:3006 را در مرورگر خود وارد کنید تا برنامه رندرشده سمت سرور را ببینید.
پیشازاین، سورس کدها بدینصورت نشان داده میشدند:
Output<div id="root"></div>
حالا با تغییراتی که ایجاد کردهایم، سورس کدها بدینصورت هستند:
Output<div id="root"><h1 data-reactroot="">Hello <!-- -->Sammy<!-- -->!</h1></div>
همانطورکه مشاهده میکنید، فعالسازی رندرینگ سمت سرور برای React App، کامپوننت <App> را با موفقیت به HTML تبدیل میکند.
جمعبندی
در این مطلب، روش مقداردهی اولیه به اپلیکیشن React و فعالکردن SSR را برای آن با اعمال برخی تنظیمات آموزش و کلیت کار را برای اپلیکیشن ساده React توضیح دادیم. طبیعتاً وقتی از مسیریابی و واکشی دادهها و redux سخن بهمیان آید، مراحل کمی پیچیدهتر خواهند بود. امیدواریم این آموزش برایتان مفید بوده باشد.
سؤالات متداول
1. منظور از فعالسازی رندرینگ سمت سرور برای React App چیست؟
رندرینگ سمت سرور که با نام اختصاری SSR نیز شناخته میشود، روشی برای رندرگرفتن از وباپلیکیشنهای تکصفحهای (SPA) است. با اجرای این تکنیک، صفحه مدنظر ابتدا کاملاً لود و سپس برای کاربر ارسال میشود.
2. مزایای SSR چیست؟
مهمترین مزیت فعالسازی رندرینگ server-side، ارتقای عملکرد و افزایش سرعت سیستم است؛ چراکه با پیادهسازی این روش، صفحه ما ابتدا کاملاً لود و بعدازآن با اولین درخواست از سرور ارسال میشود. بهعلاوه با اجرای این تکنیک، مطمئن خواهید بود که همه اِلِمانهای وبسایت شما رندر خواهند شد؛ زیرا در این روش، رندر اطلاعات به مرورگر متکی نیست.
3. معایب SSR چیست؟
بزرگترین ضعف SSR این است که نمیتواند محتواهایی که بخشی از HTML استاتیک وبسایت نیستند، تزریق کند (مثل جاوااسکریپتهایی که سرویسهای شخص ثالث وارد سیستم میکنند). بنابراین، بعضی از محتواهای صفحه (مانند محتواهای UGC) به رباتهای موتورهای جستوجو نشان داده نخواهند شد.
4. آیا روند پیادهسازی SSR برای همه پروژهها یکسان است؟
خیر، در پروژههای پیشرفتهتر مراحل انجام کار کمی متفاوت خواهد بود؛ چراکه در این پروژههای پیچیده، SSR بار زیادی را روی سرور ایجاد میکند؛ بنابراین، به تنظیمات بیشتری نیاز دارد.
5. آیا فعالسازی رندرینگ سمت سرور برای React App برای سئو وبسایت هم مفید است؟
بله، استفاده از SSR در دو صورت میتواند قدمی مثبت برای سئو سایت هم محسوب شود: ۱. زمانی که ایندکسکردن کدهای جاوااسکریپت صفحات وبسایت با مشکلاتی همراه است؛ ۲. وقتی شبکهای کُند داریم که دانلود باندل بزرگ جاوااسکریپت را دچار اختلال کرده است.