یک گوچا با تولید Next.js در Docker Compose ساخته میشود

این پست در مورد مشکل یا دامی صحبت می کند که من هنگام یادگیری Next.js و Docker به آن برخورد کردم. این بسیار ابتدایی است، اما من نتوانستم بحث های آن را آنلاین پیدا کنم. ChatGPT نیز به ویژه مفید نبود، بنابراین امیدواریم این پست باعث صرفه جویی در وقت و ناامیدی یک جدید دیگر شود.
TL;DR: می توانید قرار دهید npm run build
در فرمانی برای اجرا در هنگام شروع کانتینر، نه هنگام ساخت تصویر.
مشکل: ساختهای Docker در توسعهدهنده موفق هستند اما تولید نمیکنند
من یک فایل Docker Compose داشتم که خدمات باطن و فرانت اند را تعریف می کرد، دومی یک برنامه Next.js. من توانستم تصاویر را بسازم و کانتینرها را به خوبی در یک محیط توسعه راه اندازی کنم. اما در تولید هر بار شکست خورد!
خطا معمولاً برخی از نسخه های زیر بود:
FetchError: request to http://backend:4000/users failed
reason: getaddrinfo ENOTFOUND backend
به زبان انگلیسی ساده، زمانی که Next.js برای ساخت نسخه تولیدی برنامه اقدام کرد، frontend قادر به واکشی اطلاعات از باطن نبود.
اما در dev خوب کار کرد!!!
درست؟
رییییی؟…
اما آیا واقعاً در توسعه دهنده کار می کرد؟ آیا فرانت اند در زمان ساخت داده ها را از باطن دریافت می کرد؟
نکته: خیر
SSG و npm run build
Next.js برخی از ویژگی های عالی مانند تولید سایت استاتیک (SSG) را ارائه می دهد. تولید سایت استاتیک به این معنی است که سرور دادهها را از قبل واکشی میکند تا بتواند از آن دادهها برای تولید HTML کامل استفاده کند و سپس آن HTML را برای مرورگرهای وب در حال تولید ارائه کند. اکنون چه زمانی آیا آن داده واکشی شده است؟ جواب: در حال دویدن npm run build
(یا next build
) قبل برای شروع به سرور frontend.
بنابراین ساختن یک برنامه Next.js با قابلیت SSG آماده برای تولید، نیاز به دسترسی به داده های پشتیبان دارد. این بدان معناست که سروری که این داده ها را تامین می کند باید ابتدا راه اندازی و اجرا شود.
در مقابل، در توسعه، هیچ HTML ایستایی تولید نمیشود، بنابراین هیچ مرحله ساختی وجود ندارد که نیاز به واکشی از پیش دادهها داشته باشد.
بنابراین، در اصل، خطای من به شامل کردن خلاصه می شود RUN npm run build
در Dockerfile frontend تولید من و سپس با استفاده از Docker compose برای ساخت هر دو سرویس قبل از شروع هر کدام.
من سعی می کردم به Next.js بگویم که قبل از راه اندازی سرور بک اند برای تامین داده های لازم، یک سایت ثابت بسازد.
چطوری میشه اینو تعمیر کرد؟
این توضیح می دهد که چرا من با خطا مواجه شدم. اما چگونه آن را حل کنیم؟
اولاً، این مشکل به دلیل سردرگمی معنایی در مورد این اصطلاح، لجن زده شده است build
. Docker تصاویر را می سازد و Next.js یک سایت تولید شده به صورت ایستا می سازد. در ابتدا طبیعی است که فکر کنیم اینها عملیات مشابهی هستند که باید با هم انجام شوند.
اما هیچ ارتباط ضروری بین آنها وجود ندارد. ساختن تصویر Docker به بسته بندی یک برنامه همراه با وابستگی ها و محیط زمان اجرا بستگی دارد. ساختن سایتی که به صورت ایستا تولید میشود، موضوع واکشی دادهها و کامپایل کردن React و JavaScript در HTML بهینهسازی شده است.
اگر دادهها وجود داشته باشد که باید واکشی شوند، ساخت دوم میتواند به عنوان بخشی از اولی اتفاق بیفتد. اما، مانند مورد من، اگر دادهها وجود نداشته باشند، ساخت Next.js باید منتظر بماند.
بنابراین میتوان این مشکل را اینگونه بیان کرد: چگونه ابتدا تصاویر Docker Backend و Frontend را بسازیم، سپس سرور Backend را راهاندازی کنیم، سپس ساخت Next.js را انجام دهیم، سپس سرور frontend را راهاندازی کنیم.
نقاط ورودی داکر
نمی توانیم فقط از آن استفاده کنیم depends_on
دستورالعمل در فایل نوشتن Docker؟ depends_on
می گوید: «الف را بدون شروع B شروع نکن». و، بله، میخواهیم مطمئن شویم که خدمات باطن ابتدا شروع میشود. اما کمی بیشتر در آن وجود دارد.
همچنین باید مطمئن شویم که ساخت Next.js پس از شروع باطن انجام می شود. depends_on
یک وابستگی شروع ایجاد می کند، نه یک وابستگی ساخت. ما میتوانستیم مشکل خود را حل کنیم اگر یک دستور نوشتن Docker وجود داشت که میگوید “A را بدون شروع B ابتدا بسازید”، اما تا آنجا که من میدانم وجود ندارد.
کاری که ما می توانیم انجام دهیم این است که ساختن تصویر Docker frontend را از ساخت سایت ایستا تولید شده جدا کنیم. به این ترتیب depends_on
اطمینان حاصل می کند که ساخت Next.js در زمان مناسب اتفاق می افتد.
ساده ترین راهی که برای انجام این کار پیدا کردم با یک فایل ساده docker-entrypoint.sh است. نقاط ورودی اسکریپت هایی برای تعیین دستوراتی هستند که هنگام راه اندازی یک کانتینر اجرا شوند. دقیقا همان چیزی که ما نیاز داریم! قسمت سخت این بود که متوجه شویم ساخت Next.js می تواند در شروع کانتینر اتفاق بیفتد نه در ساخت تصویر.
فایل docker-entrypoint.sh من به این شکل بود:
#!/bin/bash
# Build the Next site including SSG
npm run build
# Start the production server
npm run start
خیلی سرراست
و مرحله آخر فقط فراخوانی نقطه ورودی به عنوان آخرین خطوط در فایل docker frontend من بود که جایگزین CMD ['npm', 'run', 'dev']
خطی که قبلاً آنجا بود:
COPY docker-entrypoint.sh /
RUN chmod +x /docker-entrypoint.sh
ENTRYPOINT ["/bin/sh", "/docker-entrypoint.sh"]
خط اول بالا اسکریپت را در تصویر داکر کپی می کند، خط دوم آن را قابل اجرا می کند و خط سوم آن را اجرا می کند.
فکر نهایی
یادگیری فنآوریهای جدید اغلب به معنای یادگیری کاربردهای مختلف یک کلمه است، برای مثال «ساخت». تصور نکنید که منظور آنها یکسان است! نسبت به کاری که کلمات در زمینه انجام می دهند حساس باشید – مفاهیم احتمالاً متفاوت هستند، شاید به طور اساسی، شاید فقط بسیار اندک. هنگامی که مفاهیم زیربنایی را روشن می کنیم، کد معمولاً دنبال می شود.