پیش رندر و هیدراسیون در توسعه وب چیست؟ شیرجه عمیق برای Devs
آیا تا به حال فکر کرده اید که Framework هایی مانند Next.js ، Gatsby.js و Remix چگونه کار می کنند؟
این فریم ورک ها از مفاهیم پیش رندر و هیدراسیون استفاده می کنند که نشان دهنده پیشرفت های قابل توجهی در تاریخ توسعه وب است.
این چارچوبها از این مفاهیم برای ایجاد زنجیرههای ابزاری استفاده میکنند که اپلیکیشنهای وب کارآمد را میسازند. در این مقاله، پیش رندر و هیدراسیون و اینکه چرا آنها ویژگی های مهمی هستند که هنگام ساخت برنامه های تک صفحه ای استفاده می شوند، بحث خواهیم کرد.
برای درک این مفاهیم، باید تحلیل کنیم که چرا آنها ایجاد شده اند و آنها سعی در حل چه مشکلی دارند. بیایید نگاهی به آغاز برنامه های کاربردی وب بیندازیم.
فهرست مطالب
توسعه وب در گذشته: رندر سنتی سمت سرور
رندر سنتی سمت سرور در مقابل برنامه های کاربردی تک صفحه ای
ورود به دنیای جدید با پیش رندر و هیدراسیون
تولید سایت استاتیک (SSG) چیست؟
خطاهای احتمالی هنگام کار با فریمورک های پیش رندر و هیدراسیون
خطای Using Client-Only Properties
چه ارتباطی با فریمورک هایی مانند Gatsby.js، Next.js و Remix دارد؟
توسعه وب در گذشته: رندر سنتی سمت سرور
در زمان رندر سنتی سمت سرور، رندر و تعامل از هم جدا شدند. ما از زبان های سمت سرور مانند Node.js ، PHP ، Java و Ruby on Rails استفاده کردیم.
در سرورهای خود، نماها را با استفاده از زبانهای قالب مانند JSP و EJS ایجاد کردیم. نماها صفحات HTML هستند و میتوانید جاوا اسکریپت یا جاوا را درون آنها تزریق کنید تا عملکرد، دادههای پویا بازیابی شده از جستارهای پایگاه داده و بخشهای تعاملی با زبانهایی مانند JQuery را اضافه کنید.
جنبه منفی رندر سنتی سمت سرور
مسائل مربوط به عملکرد
هر بار که کاربر صفحه ای را درخواست می کند، باید یک درخواست از سرور انجام شود!
این به این معنی بود که یک صفحه کامل بارگذاری مجدد خواهد شد.
پرس و جوهای پیچیده می تواند منجر به سرعت کمتر شود.
چالش های مقیاس پذیری
دسترسی جهانی : یک CDN پویا برای ذخیره فایلهای پویا مورد نیاز بود. CDN ها برای محتوای استاتیک مناسب تر هستند، اما شرکت هایی مانند Cloudflare Cloudflare-Workers را برای کمک به این فرآیند ایجاد کردند.
ارتقاء مقیاس سرورها : اگر کاربران بیشتری از برنامه استفاده کنند، تقاضا برای سرور افزایش می یابد. ممکن است نیاز به سرمایه گذاری بیشتر در منابعی مانند افزایش مقیاس با گفت ن سرورهای بیشتر داشته باشید.
منطق تکراری
ممکن است کد تکراری داشته باشید. برای مثال، اگر میخواهید فیلدهای فرم را تأیید کنید، باید هم در فایل EJS و هم در نقطه پایانی API خود اعتبارسنجی کنید.
بیایید به قطعه کد زیر نگاه کنیم تا نمونه ای از این منطق تکراری را ببینیم:
کد در EJS:
<form action= '/submit-form' method= 'POST' id= "myForm" > < label for = "email" > Email: </ label > < input type = "email" id = "email" name = "email" /> < button type = "submit" > Submit </ button > </form> < script > document .getElementById( 'myForm' ) .addEventListener( 'submit' , function ( event ) { const email = document .getElementById( 'email' ).value; if (!email.includes( '@' )) { alert( 'Please enter a valid email.' ); event.preventDefault(); } }); </ script >
کد در Express.js:
import express from "express" ; const app = express(); const path = require ( "path" ); const port = 3000 ; // To received form data app.use( express.urlencoded({ extended : true , }), ); // view engine setup. Need a folder called views app.set( "views" , path.join(__dirname, "views" )); app.set( "view engine" , "ejs" ); app.get( "/" , ( req, res ) => { // To render the view res.render( "index" , { errors : null }); }); app.post( "/submit-form" , ( req, res ) => { const email = req.body.email; if (!email.includes( "@" )) { res.status( 400 ).send( "Invalid email." ); return ; } // Proceed with form processing }); app.listen(port, () => { console .log( `Sandbox listening on port ${port} ` ); });
رندر سنتی سمت سرور دارای معایب قابل توجهی بود، اما معرفی اپلیکیشن های تک صفحه ای دوران جدیدی را در توسعه وب نشان داد.
رندر سنتی سمت سرور در مقابل برنامه های کاربردی تک صفحه ای
برنامه تک صفحه ای (SPA) چیست؟
یک برنامه تک صفحه ای (SPA) یک پیاده سازی برنامه وب است که تنها یک سند وب را بارگیری می کند و سپس محتوای بدنه آن سند را از طریق API های جاوا اسکریپت مانند Fetch به روز می کند زمانی که محتوای متفاوتی نمایش داده می شود. به کاربران اجازه می دهد تا از وب سایت ها بدون بارگیری صفحات جدید از سرور استفاده کنند. ( منبع: MDN )
یک راه محبوب برای پیاده سازی SPA استفاده از React است. React به شما امکان می دهد برنامه های سریع ایجاد کنید و به روز رسانی UI را راحت تر از روش های دستکاری DOM ساده می کند.
چندین مزیت را ارائه می دهد:
تجربه کاربری بهبود یافته
یک SPA یک فایل HTML واحد را بارگیری می کند و به صورت پویا محتوا را با تعامل کاربر با آن به روز می کند. همه این کارها بدون بارگذاری مجدد کامل صفحه انجام می شود.
SPA می تواند وضعیت رابط کاربری را به راحتی به روز کند و بازخورد فوری را بر اساس اقدامات انجام شده در برنامه به کاربران ارائه دهد.
کاهش بار سرور
بیشتر کار توسط مرورگر انجام می شود. این باعث کاهش بار روی سرور می شود!
مقیاس پذیری بهتر
مرورگر اکنون بیشتر کار را انجام می دهد. اکنون می توانیم سرورهای اختصاصی متمرکز بر ارائه داده ها از طریق API ها را مستقر کنیم. ما به راحتی می توانیم به صورت افقی مقیاس بندی کنیم. ما این امکان را داریم که از سرورها یا عملکردهای بدون سرور مانند AWS lambda استفاده کنیم.
یک SPA را می توان روی یک CDN ثابت مانند Netlify میزبانی کرد.
با اضافه شدن زنجیرههای ابزاری مانند Vite و Create React App برای خودکارسازی راهاندازی یک برنامه جاوا اسکریپت مدرن، مهندسان دیگر نگران پیکربندی Webpack به صورت دستی نبودند.
پیاده سازی SPA ها دارای معایبی است. نکته مهم این است که برای بارگیری همه جاوا اسکریپت و HTML برای ما به مرورگر متکی است. این بدان معنی است که در دستگاه های تلفن همراه و برای افرادی که اینترنت کند دارند، کاربران ممکن است در دیدن صفحه با تاخیر مواجه شوند. برای توضیح این موضوع، جریان را تحلیل می کنیم:
جریان برنامه تک صفحه
چندین مرحله لازم است تا کاربران در نهایت صفحه HTML را ببینند.
ابتدا مرورگر HTML را واکشی می کند. این HTML اولیه خالی و نادرست خواهد بود. چرا؟ زیرا محتوا از جاوا اسکریپت می آید. این به این معنی است که مرورگر زمان می برد تا جاوا اسکریپت را واکشی کند، آن را بارگذاری کند و آن را اجرا کند. از آنجایی که HTML اولیه اشتباه است، خزنده های وب و موتورهای جستجو محتوای مرتبط را در وب سایت پیدا نمی کنند و از آن صرف نظر می کنند.
به GIF زیر نگاهی بیندازید. در اینجا جاوا اسکریپت در ابزار برنامهنویس Chrome غیرفعال است. وب سایت بدون جاوا اسکریپت بارگیری نمی شود. اگر جاوا اسکریپت فعال باشد اما اتصال اینترنت کند باشد، کاربران ممکن است صفحه خالی را برای مدت طولانی ببینند.
این یک مشکل بزرگ بود. این امر منجر به توسعه وب به دوره قبل از رندر شد.
ورود به دنیای جدید با پیش رندر و هیدراسیون
چرا پیش رندرینگ مهم است؟
مردم متوجه شدند که ما می توانیم HTML را از قبل تولید کنیم. بسته به روش های مورد استفاده می تواند از سرور ما یا در زمان ساخت تولید شود.
پیش رندر به دو روش انجام می شود - رندر سمت سرور (SSR) یا تولید سایت ایستا (SSG)
رندر سمت سرور چیست؟
اجزای React بر روی سرور رندر می شوند و HTML حاصل به مرورگر ارسال می شود. این می تواند سئو و زمان بارگذاری اولیه را بهبود بخشد. فرآیند رندر در هر درخواست صفحه رخ می دهد.
تولید سایت استاتیک (SSG) چیست؟
صفحات HTML ایستا در زمان ساخت تولید می شوند. این صفحات را می توان به سرعت بدون نیاز به سرور برای ارائه آنها در پرواز ارائه کرد.
هر دو روش مفید است! حالا HTML که کاربر دریافت می کند صحیح خواهد بود. آنها یک صفحه حاوی محتوا را به جای صفحه خالی که با استفاده از Vite یا Create React App مشاهده می شود، می بینند.
اما یک مشکل وجود دارد: HTML دریافتی کاربر تعاملی نیست. آنها نمی توانند روی آن کلیک کنند یا فرم ارسال کنند. چگونه می توانیم تعامل را به برنامه خود اضافه کنیم؟ با آبرسانی مناسب🚰 🌊!
هیدراتاسیون چیست؟
هیدراتاسیون چیزی است که تعامل را به برنامه ما اضافه می کند. جاوا اسکریپت را بارگیری می کند که برنامه ما را تعاملی می کند.
در React، «هیدراتاسیون» به این معناست که React چگونه به HTML موجودی که قبلاً توسط React در یک محیط سرور رندر شده بود، متصل میشود. در طول هیدراتاسیون، React تلاش میکند شنوندگان رویداد را به نشانهگذاری موجود متصل کند و رندر برنامه را بر روی مشتری بر عهده بگیرد. ( منبع: React Docs )
بیایید ببینیم جریان برنامهای که از Pre-Render و Hydration استفاده میکند چگونه است:
آشتی چیست؟
آشتی فرآیندی است که توسط آن React کارآمدترین راه را برای به روز رسانی UI در پاسخ به تغییرات در داده ها یا سلسله مراتب اجزا تعیین می کند. (منبع: تفاوت DOM مجازی و واقعی (React) چیست؟ )
آشتی زمانی اتفاق میافتد که React نحوه بهروزرسانی رابط کاربری را در پاسخ به تغییرات در سلسله مراتب دادهها یا مؤلفهها مشخص میکند.
هنگامی که کامپوننت ها رندر می شوند، یک DOM مجازی ایجاد می شود. اگر تغییراتی در وضعیت یا props وجود داشته باشد، یک DOM مجازی جدید ایجاد می شود. سپس React از الگوریتم diff خود برای مقایسه Virtual DOM جدید با Virtual DOM قبلی برای تحلیل تغییرات استفاده می کند. این آشتی است.
بر اساس تغییرات یافت شده، React قرار نیست کل رابط کاربری را به روز کند . در عوض، عناصری را که باید به روز شوند را انتخاب می کند. این مقاله به من در درک آشتی کمک کرد.
پیش رندر و هیدراتاسیون در عمل
در جریان Pre-Rendering و Hydration، ابتدا کاربر HTML را با محتوای صحیح می بیند.
سپس Hydration وارد می شود و جاوا اسکریپت را بارگذاری می کند تا تعاملی را به برنامه بدهد.
بیایید روند را شبیهسازی کنیم که اگر فرآیند Hydration زمان زیادی طول بکشد (به دلیل اتصال اینترنت کند) یا اگر کاربر جاوا اسکریپت را غیرفعال کند، چه اتفاقی میافتد.
اینجا یک گیف است که جاوا اسکریپت را در نمونه کار خود غیرفعال می کنم. من پورتفولیوی خود را با استفاده از گتسبی یک فریمورک تولید سایت استاتیک ایجاد کردم (همچنین دارای قابلیت رندر سمت سرور است):
حتی با وجود اینکه جاوا اسکریپت وجود ندارد، من همچنان میتوانم محتوای نمونه کار خود را ببینم. دلیلش این است که کاربر HTML پیش رندر دریافت کرده است! میتوانید ببینید که من نمیتوانم روی آیتمهای منوی کشویی یا دکمههایی که میگویند درباره من، پروژهها، و تجربه کلیک کنم. دلیل آن این است که جاوا اسکریپت بارگیری نشده است پس کاربر نمی تواند با آن تعامل داشته باشد.
مدل ذهنی برای هیدراتاسیون
جاش کومئو یک مدل ذهنی جالب برای هیدراسیون ایجاد کرد. جاش آن را "رندر دو پاس" می نامد.
اولین پاس، در زمان کامپایل، تمام محتوای غیر شخصی ثابت را تولید می کند و حفره هایی را ایجاد می کند که محتوای پویا در آن جا خواهد رفت. سپس، پس از اینکه برنامه React روی دستگاه کاربر نصب شد، یک پاس دوم در تمام بیتهای پویا که به وضعیت کلاینت بستگی دارد، نشان میدهد. (منبع: The Perils of Hydration )
برای جمع بندی:
The First Pass : کاربر HTML پیش رندر را می بیند. حاوی محتوای ثابت است، اما محتوای پویا را ندارد.
گذر دوم: جاوا اسکریپت بارگیری را شروع می کند و قطعات پویا از دست رفته را که به وضعیت مشتری بستگی دارد پر می کند.
خطاهای احتمالی هنگام کار با فریم ورک های پیش رندر و هیدراسیون
هنگام کار با فریم ورک هایی مانند Next.js، سرور HTML پیش رندر ثابت را برمی گرداند و سپس Hydration رخ می دهد که جاوا اسکریپت را بارگیری می کند.
اما هنگام کار با داده های پویا و ویژگی های فقط مشتری باید مراقب باشیم. برای مثال به این کد نگاه کنید:
خطای داده پویا
function HydrationErrors ( ) { return ( <> < h1 > Hydration Errors </ h1 > < div > < p > Today date in milliseconds is {new Date().getTime()} </ p > </ div > </> ); }
در اینجا سرور HTML را با مهر زمانی در میلی ثانیه تولید می کند. به عنوان مثال: 1724869161034
. فرآیند Hydration شروع می شود و سپس مشتری HTML را بارگذاری می کند. زمان گذشته است و مهر زمانی متفاوت است، اکنون 172486193750
است! این سناریو باعث خطای زیر می شود:
از سرور و خطای هیدراتاسیون مشتری." width="977" height="788" loading="lazy">
این به این دلیل اتفاق می افتد که تابع getTime()
مهر زمانی متفاوتی تولید می کند.
این بدان معنی است که سرور و مشتری HTML متفاوتی تولید می کنند. برگه شبکه پاسخ سرور را به ما نشان می دهد. این یک HTML متفاوت از آنچه مشتری بارگذاری می کند است.
پاسخ سرور در زیر:
است. " width="904" height="836" loading="lazy">
پاسخ مشتری در زیر:
است. " width="1624" height="853" loading="lazy">
برای رفع خطا:
function HydrationErrors ( ) { const [date, setDate] = useState<number>(); useEffect( () => { setDate( new Date ().getTime()); }, []); return ( <> < h1 > Hydration Errors </ h1 > < div > < p > Today date in milliseconds is {date} </ p > </ div > </> ); }
می توانید از قلاب useEffect
استفاده کنید. چرا این کار می کند؟ زیرا HTML ای که سرور و کلاینت ارائه می کنند حاوی یک متغیر وضعیت date
خالی خواهد بود.
هنگامی که کامپوننت نصب شد، useEffect
فعال می شود و داده های پویا را از متغیر حالت اضافه می کند یا می توانید از پرچم suppressHydrationWarning
استفاده کنید و آن را روی true تنظیم کنید.
<p suppressHydrationWarning={ true }>Today date in milliseconds is {date}</p>
خطای Using Client-Only Properties
به خاطر داشته باشید که نمی توانید از window
یا localStorage
استفاده کنید. آنها در سرور وجود ندارند. مثال زیر را در نظر بگیرید:
function HydrationErrors ( ) { return ( <> < div > {typeof window !== "undefined" && < p > This p tag will appear </ p > } </ div > </> ); }
در اینجا، سرور HTML را با یک تگ خالی <div>
برمی گرداند، اما سرویس گیرنده HTML حاوی تگ <p>
را بارگذاری می کند. این یک خطای هیدراسیون ایجاد می کند!
این خطایی است که دریافت می کنید:
از خطای هیدراتاسیون ویژگی های سمت مشتری استفاده کرد. " width="952" height="778" loading="lazy">
برگه شبکه پاسخ سرور را به ما نشان می دهد. یک تگ <div>
خالی است.
پاسخ سرور در زیر:
است. " width="908" height="850" loading="lazy">
اما مشتری HTML را بارگذاری می کند که می گوید "این تگ p ظاهر خواهد شد".
پاسخ مشتری در زیر:
است. " width="1618" height="835" loading="lazy">
این نسخه ی نمایشی از Deeecode The Web در چرا خطاهای هیدراسیون وجود دارند الهام گرفته شده است؟ و نحوه حل آنها . او توضیح بسیار خوبی در مورد اینکه چرا خطاهای هیدراسیون رخ می دهد می دهد. تماشای آن را توصیه می کنم!
چه ارتباطی با فریم ورک هایی مانند Gatsby.js، Next.js و Remix دارد؟
همه چیزهایی که در مورد آن بحث کردیم، همان چیزی است که همه این چارچوب ها روی آن تمرکز دارند.
Static-Site Generation و Server-Side Rendering را می توان با استفاده از Gatsby.js، Next.js و Remix پیاده سازی کرد. آنها بر روی ایجاد یک HTML پیش رندر آماده برای مشاهده توسط کاربر تمرکز می کنند، سپس Hydration را برای گفت ن تعامل به برنامه آغاز می کنند.
Gatsby.js، Next.js و Remix جایگزین مفهوم برنامههای تک صفحهای نمیشوند - آنها به فرآیند اضافه میکنند. به این جریان نگاه کنید:
این به جریان فعلی SPA اضافه می کند! اگر پیش رندر نداشتید، فرآیند از جایی شروع می شود که جعبه صورتی شروع می شود، با یک HTML ناقص.
حرکت رو به جلو
این مقاله به عنوان مقدمه ای بر پیش رندر و هیدراتاسیون است.
Next.js ابتدا این مفاهیم را با روتر Pages پیاده سازی کرد. Pages Router عالی بود و توابعی مانند getServerSideProps
، getStaticPaths
و getStaticProps
برای پیاده سازی Static-Site Generation و Server-Side به دنیا معرفی کرد.
این پیاده سازی ها مزایا و معایب خود را داشتند. به عنوان مثال، Josh W Comeau اشاره کرد که با getServerSideProps
:
این استراتژی فقط در سطح مسیر، برای اجزای بالای درخت کار می کند. ما نمی توانیم این کار را در هیچ جزء انجام دهیم.
هر متا چهارچوب با رویکرد خاص خود آمد. Next.js یک رویکرد دارد، گتسبی رویکردی دیگر، ریمیکس رویکرد دیگری دارد. استاندارد نشده است
همه اجزای React ما همیشه روی مشتری هیدراته می شوند، حتی زمانی که نیازی به انجام این کار نباشد.
تیم React نیز این را دید و پارادایم جدیدی به نام React Server Components (RSC) ایجاد کرد. برای پیاده سازی RSC، تیم Vercel App Router را ایجاد کرد. App Router هنوز از مفاهیم پیش رندر و هیدراتاسیون استفاده می کند، اما دیگر از getStaticProps
، getStaticPaths
و getServerSideProps
استفاده نمی کند. از RSC و دیگر آپشن های عالی App Router برای پیادهسازی برنامههای وب بهتر استفاده میکند. توصیه میکنم در صورت فرصت به App Router نگاهی بیندازید.
نتیجه گیری
ممنون که تا اینجا خوندید 😃!
من از نوشتن این مقاله چیزهای زیادی یاد گرفتم. من این تحقیق را شروع کردم زیرا از گتسبی برای ایجاد نمونه کارها نسخه 4 و Next.js در کارم استفاده کردم، اما مفاهیم پشت این چارچوب ها و دلیل ایجاد آنها را درک نکردم.
من یک برنامه وب ساختم تا موضوعات تحت پوشش مقاله را نشان دهم.
برنامه: https://the-nextjs-pagesrouter-guide.vercel.app/
Repo GitHub: https://github.com/salvillalon45/the-nextjs-pagesrouter-guide
در مخزن GitHub می توانید کدهای زیر را پیدا کنید:
صفحه ای که getStaticProps و getStaticPaths را پیاده سازی می کند
صفحه ای که getStaticProps را پیاده سازی می کند
صفحه ای که getServerSideProps را با واکشی سمت کلاینت اجرا می کند
صفحه ای برای نشان دادن خطاهای هیدراسیون
استفاده از دایرکتوری API برای پیاده سازی مسیرهای API خودمان
منابع
در اینجا برخی از منابع آموزشی کلیدی است که برای نوشتن این مقاله استفاده کردم، در صورتی که می خواهید عمیق تر در آن کاوش کنید:
هیدراتاسیون چیست ؟ توسط سازنده
REACT HYDRATION دقیقا چیست؟ و چرا اهمیت دارد؟ توسط Deeecode The Web
چگونه NextJS واقعا کار می کند توسط تئو براون
Next.js - GetServerSideProps در مقابل GetStaticProps توسط Morado Web Development
ارسال نظر