localhost کار میکند، هنوز دو مسئله حل نشده است: چطور آن را به کسی بیرون از کامپیوترت نشان بدهی، و چطور مطمئن شوی روی گوشی او هم درست کار میکند؟ در این آموزش، یک مسیر عملی برای انتشار نسخهٔ اولیه میسازیم: اول اجرای محلی را سالم میکنیم، بعد میان لینک موقت و میزبانی پایدار انتخاب میکنیم، کلیدها را از فایلهای عمومی دور نگه میداریم و در پایان نسخهٔ موبایلی و PWA را آزمایش میکنیم. نمونهٔ همراه ما اپ ثبت گزارش صوتی «آوای مزرعه» است، اما همین مسیر برای یک وباپ کوچک دیگر هم کاربرد دارد.
۱. قبل از انتشار، مطمئن شو اپِ درست را باز کردهای
localhost نام کامپیوتر خود تو از دید همان دستگاه است. عدد بعد از آن، مثل 3001، پورت برنامه است. اگر دو پروژهٔ وب را همزمان اجرا کرده باشی، ممکن است یکی روی پورت 3000 و دیگری روی 3001 باشد. باز شدن یک صفحه در مرورگر بهتنهایی ثابت نمیکند پروژهٔ موردنظرت را اجرا کردهای.
از پوشهٔ پروژه، دستور اجرای ثبتشده در فایل راهنمای آن یا بخش scripts فایل package.json را بررسی کن. سپس خروجی ترمینال را بخوان و دقیقاً همان آدرس و پورت را باز کن. در این پروژه، هنگام ادامهٔ کار، پورت 3000 صفحهٔ پروژهٔ دیگری را نشان میداد و اجرای اپ روی 3001 بررسی شد. اگر صفحهای نامربوط دیدی، پیش از دستکاری کد، پورتها و فرایندهای در حال اجرا را چک کن. نتیجهٔ این مرحله باید ساده باشد: عنوان و رفتار اپ خودت را در آدرس محلی درست ببینی.
حالا یک مسیر کوتاه را امتحان کن؛ مثلاً ضبط یک صدا و دیدن آن در صف. اگر همین مسیر در اجرای محلی خراب است، انتشار فقط پیدا کردن علت خطا را سختتر میکند. وقتی یک نقطهٔ سالم پیدا کردی، تغییرات مرتبط را در Git مرور و commit کن تا در صورت خراب شدن مرحلهٔ انتشار، نسخهٔ قابلآزمایش قبلی را داشته باشی. راهنمای Git برای تفاوت commit محلی و فرستادن آن به مخزن راه دور مفید است.
۲. برای نمایش موقت، localhost را با ngrok بیرون ببر
آدرس localhost:3001 را نمیتوانی برای دوستی بفرستی و انتظار داشته باشی اپ تو را ببیند؛ localhost روی گوشی او به خودِ گوشی اشاره میکند. حتی آدرس IP محلی کامپیوترت معمولاً فقط در شبکهٔ داخلی قابلدسترسی است. برای یک نمایش کوتاه، ngrok میتواند یک نشانی اینترنتی موقت را به پورت برنامهٔ در حال اجرای تو وصل کند.
بعد از نصب و راهاندازی ngrok طبق راهنمای آن، اپ را روی پورت درست روشن نگه دار و در ترمینالی جداگانه اجرا کن:
ngrok http 3001
این یک دستور ترمینال است، نه پرامپت برای دستیار هوش مصنوعی. در خروجی ngrok باید نشانیای ببینی که به localhost:3001 هدایت میشود. آن نشانی را ابتدا در مرورگر خودت و سپس، برای آزمایش واقعی، روی گوشی با اینترنت موبایل باز کن. اگر صفحه روی گوشی باز نشد، روشن بودن خود اپ، درست بودن پورت و فعال بودن تونل را بهترتیب بررسی کن.
این راه برای تست است، نه جایگزین میزبانی دائمی. با متوقف شدن تونل یا خاموش شدن کامپیوتر، لینک دیگر اپ را نمایش نمیدهد. ضمن اینکه هر کسی که به لینک دسترسی پیدا کند ممکن است بتواند با اپ آزمایشی تعامل کند؛ دادهٔ حساس یا قابلیت بدون کنترل دسترسی را صرفاً به امید موقت بودن لینک عمومی نکن.
۳. وقتی لینک باید بماند، نوع میزبانی را از روی نیاز انتخاب کن
برای اینکه اپ بدون روشن ماندن کامپیوترت در دسترس باشد، باید فایلهای آن را روی سرویس میزبانی قرار بدهی. اما «میزبانی» یک انتخاب واحد نیست. یک صفحهٔ ایستا میتواند روی میزبانی فایل منتشر شود؛ برنامهای که باید کد سمت سرور اجرا کند، به محیط اجرای مناسب همان کد نیاز دارد. سرور مجازی کنترل بیشتری میدهد، ولی مسئولیت راهاندازی، نگهداری و بررسی خطاهایش هم با تو است.
پیش از انتخاب سرویس، سه سؤال بپرس: آیا اپ فقط رابط کاربری و درخواست به یک سرویس خارجی دارد؟ آیا کد اختصاصی باید دور از مرورگر اجرا شود؟ آیا دادهها باید میان چند حساب با سطح دسترسی متفاوت به اشتراک گذاشته شوند؟ اگر پاسخ دو سؤال آخر مثبت است، انتشار صرفِ فایلهای فرانتاند مسئله را حل نمیکند.
Vercel هم در میان گزینههای مطرحشده است، اما در این مسیر اپ روی آن منتشر نمیشود. بنابراین آن را نتیجهٔ انجامشده یا راهحل قطعی این پروژه حساب نکن. اگر بعداً انتخابش کردی، ابتدا ببین خروجی پروژه و کد سمت سرورت با روش استقرار موردنیازت سازگار است؛ نقطهٔ شروع، مستندات استقرار Vercel است. دربارهٔ هزینه و محدودیتهای هر سرویس نیز به اطلاعات روز خود سرویس رجوع کن، نه عددی که زمانی در یک آموزش دیدهای.
۴. نسخهٔ ساده را روی AI Pass Spaces منتشر و واقعاً امتحان کن
برای نسخهٔ اولیهٔ آوای مزرعه، مسیر انتخابشده AI Pass Spaces بود. این مسیر برای اپی مطرح شد که رابط کاربریاش در مرورگر اجرا میشود و برای بعضی کارها، مانند درخواست هوش مصنوعی و نگهداری دادهٔ ساده، به امکانات AI Pass تکیه دارد. انتشار در Spaces به این معنا نیست که هر برنامهٔ دلخواهی را میتوان بدون تغییر، با بکاند اختصاصیاش آنجا اجرا کرد.
اگر همین مسیر را برای پروژهٔ خودت انتخاب میکنی، وارد حساب AI Pass شو، بخش Spaces را باز کن و فضای انتشار متعلق به خودت را بساز یا انتخاب کن. در همان پنل، راهنمای ساخت اپ با عامل و روش فعلی انتشار را پیدا کن و در اختیار ابزار توسعه بگذار؛ اگر نام گزینهها تغییر کرده است، به راهنمای داخل پنل رجوع کن. از ابزار بخواه پیش از انتشار، سازگاری خروجی پروژه با Spaces، نیاز احتمالی به کد سمت سرور و شناسهٔ فضای مقصد را مشخص کند. شناسه یا تنظیمات متعلق به سازندهٔ نمونه را برای اپ خودت نگه ندار. اگر انتشار به اعتبارنامه نیاز دارد، آن را فقط طبق راهنمای سرویس و در تنظیمات خصوصی محیط خودت قرار بده، نه در فایل عمومی یا سکیلی که commit میشود. فایلهای تغییرکرده و مقصد انتشار را پیش از تأیید بررسی کن. برای سپردن این کار به یک عامل کدنویسی، این متن فقط بازنویسی آموزشی پرامپت است؛ نه متنی که باید آن را عیناً از پروژهٔ نمونه کپی کنی:
پروژه را بررسی کن و برای انتشار نسخهٔ فعلی روی AI Pass Spaces برنامه بده. پیش از تغییر فایلها مشخص کن کدام بخشها در مرورگر اجرا میشوند، کدام بخشها به سرویس خارجی وابستهاند و چه خروجیای برای انتشار لازم است. هیچ کلید یا شناسهٔ متعلق به شخص دیگری را وارد نکن. پس از تغییرات، روش ساخت خروجی و یک آزمون دستی برای لینک منتشرشده را توضیح بده.
در پروژهٔ نمونه، لینک منتشرشده در نخستین باز کردن درست نمایش داده نشد و با تازهسازی صفحه باز شد؛ اصلاح ایرادهای بعدی هم به انتشار نسخهٔ تازه نیاز داشت. پس معیار پایان کار، پیام موفقیت ابزار نیست: لینک را باز کن، صفحه را تازهسازی کن و یک کار واقعی انجام بده. اگر پروژهات با Next.js یا ابزار ساخت دیگری نوشته شده، فرض نکن خودِ پوشهٔ سورس یا هر خروجی ساخت، خودبهخود یک فایل HTML مستقل است؛ خروجی قابلانتشار را بر اساس ساختار واقعی پروژه بررسی کن.
۵. مرز Spaces و بکاند اختصاصی را دقیق نگه دار
فرانتاند کدی است که مرورگر کاربر دریافت و اجرا میکند؛ بکاند کدی است که در محیطی جدا از مرورگر، درخواستها و دسترسیها را مدیریت میکند. در نمونهٔ آوای مزرعه، رابط منتشرشده در Spaces از قابلیتهای AI Pass برای تماسهای هوش مصنوعی و نگهداری سادهٔ داده استفاده میکرد. پس «بکاند اختصاصی نداریم» با «هیچ سرویس سمت سروری در کار نیست» فرق دارد.
این تمایز وقتی مهم میشود که بخواهی یک مدیر گزارشهای چند کاربر را ببیند، اما هر کاربر فقط گزارشهای مجاز خودش را. چنین رفتاری با یک رمز نمایشی در فرانتاند یا ورود همه با یک حساب، ایمن نمیشود. رمزهای سادهٔ نسخهٔ نمایشی را برای استفادهٔ واقعی نگه ندار؛ تا پیش از طراحی حسابها و مجوزهای مستقل، لینک عمومی را فقط با داده و صدای آزمایشیِ غیرحساس امتحان کن. باید هویت، مجوز هر درخواست و محل نگهداری داده را طراحی کنی. محدودیت مشاهدهٔ گزارشها با حسابی دیگر در همین پروژه نشان داد که مدل سادهٔ ذخیرهسازی آن برای سناریوی مدیریت چندکاربره کافی نیست؛ این نتیجه، حکم کلی دربارهٔ تمام امکانات یک پلتفرم نیست.
در این نقطه میتوانی معماری دیگری با بکاند و پایگاه دادهٔ متناسب انتخاب کنی و، اگر مناسب بود، بخش هوش مصنوعی را همچنان به سرویس جداگانه بسپاری. انتخاب را با نیاز واقعی انجام بده: برای نمونهٔ شخصی شاید رابط ساده کافی باشد، اما برای دادهٔ مشترک چند نفر، کنترل دسترسی را به مرحلهٔ آخر موکول نکن.
۶. کلید انتشار و کلید مصرف هوش مصنوعی را قاطی نکن
برای انتشار ممکن است به اعتبارنامهای نیاز داشته باشی که به ابزار اجازهٔ بارگذاری فایل میدهد. درخواست هوش مصنوعی نیز ممکن است اعتبارنامه یا اتصال حساب کاربر بخواهد. این دو نقش را جدا بررسی کن. اگر کلید خصوصی را در JavaScript ارسالی به مرورگر بگذاری، کاربران میتوانند کد یا درخواستهای شبکه را ببینند. برای تنظیمات خصوصیِ اجرای محلی میتوانی از .env.local استفاده کنی، به شرطی که آن را منتشر نکنی. این نام فایل بهتنهایی از کلید محافظت نمیکند: اگر مقدار را در کد مرورگر یا متغیر عمومیِ زمان ساخت، مانند متغیرهای دارای پیشوند NEXT_PUBLIC_ یا VITE_، به کار ببری، ممکن است وارد خروجی عمومی شود. خروجی ساخت، درخواستهای Network و لاگها را هم بررسی کن.
پیش از هر commit، فایلهای stageشده و تنظیمات .gitignore را بازبینی کن؛ .gitignore فایل یا کلیدی را که پیشتر در Git ثبت شده است از تاریخچه حذف نمیکند. کلید را در گفتوگو با عامل، سکیلِ قابلانتشار یا لاگ هم قرار نده. اگر کلیدی حتی یکبار به مخزن عمومی رفته، پاککردنش در commit بعدی کافی نیست؛ نسخهٔ قبلی ممکن است در تاریخچه بماند. آن کلید را از سمت ارائهدهنده باطل یا تعویض کن و سپس تاریخچه و مسیر انتشار را بررسی کن. برای محیط میزبانی نیز تنظیمات امن همان محیط را به کار ببر؛ فرض نکن فایل محلی .env.local همراه پروژه منتقل میشود.
در نمونه، اتصال حساب AI Pass بهعنوان راهی برای استفاده از حساب خودِ کاربر در قابلیت هوش مصنوعی مطرح شد. این روش میتواند نیاز به قرار دادن کلید خصوصی سازنده در رابط عمومی را کم کند، اما به معنی غیرقابلسرقت بودن توکنها یا بینیازی از بررسی مجوزها نیست. روی دستگاه دیگر، بدون ورود به حساب خودت، مسیر اتصال، رد کردن مجوز و خطای درخواست را هم امتحان کن.
۷. PWA را برای تجربهٔ نصبشدنی بساز، نه بهعنوان وعدهٔ آفلاین بودن همهچیز
PWA یا Progressive Web App همچنان یک وباپ است که با تنظیماتی مانند manifest و service worker میتواند در مرورگرهای پشتیبانیشده تجربهای نزدیکتر به اپ نصبشدنی بدهد. manifest اطلاعاتی مثل نام و آیکون را معرفی میکند؛ service worker میتواند بعضی درخواستها و فایلهای رابط را مدیریت کند. هیچکدام بهتنهایی تماس هوش مصنوعی را بدون اینترنت انجام نمیدهند. برای جزئیات رفتار مرورگرها، راهنمای PWA در MDN را ببین.
در آوای مزرعه، هدف این بود که صدا پیش از دسترسی به اینترنت روی همان دستگاه در صف بماند و کاربر بعداً با یک دکمه ارسال و پردازش را آغاز کند. PWA شدن بهتنهایی این قابلیت را ایجاد نمیکند: خودِ ضبط، نگهداری فایل صوتی ــ مثلاً در IndexedDB ــ و نمایش وضعیتهایی مانند «در انتظار ارسال»، «در حال پردازش» و «نیازمند تلاش دوباره» باید پیادهسازی و آزمایش شوند. پس از یک بار باز کردن اپ، قطع اینترنت، تازهسازی صفحه و ضبط یک مورد تازه را جداگانه امتحان کن؛ ورود به حساب و پردازش هوش مصنوعی ممکن است همچنان اینترنت بخواهند. دادهٔ مرورگر را همارز ذخیرهٔ مطمئن روی سرور ندان: پاک شدن دادههای سایت، محدودیت فضا یا تغییر دستگاه میتواند به صف محلی آسیب بزند.
مثال تکمیلی آموزشی: برای فهمیدن نقش service worker، یک پوشهٔ جدا به نام pwa-check بساز. سه فایل زیر را دقیقاً در ریشهٔ همین پوشه قرار بده. این نمونه فقط صفحهٔ آزمایشی را برای بازشدن دوباره ذخیره میکند؛ ضبط صدا، صف و ارسال هوش مصنوعی ندارد و کد پروژهٔ آوای مزرعه نیست.
فایل pwa-check/index.html:
<!doctype html>
<html lang="fa" dir="rtl">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="manifest" href="/manifest.webmanifest">
<title>آزمون انتشار</title>
</head>
<body>
<h1>صفحهٔ آزمایشی باز شد</h1>
<p>پس از یک بار بارگذاری، حالت آفلاین را امتحان کن.</p>
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js').catch(console.error);
}
</script>
</body>
</html>
فایل pwa-check/manifest.webmanifest:
{
"name": "آزمون انتشار وباپ",
"short_name": "آزمون اپ",
"start_url": "/",
"display": "standalone"
}
فایل pwa-check/sw.js:
const CACHE = 'pwa-check-v1';
self.addEventListener('install', event => {
event.waitUntil(caches.open(CACHE).then(cache => cache.addAll(['/'])));
});
self.addEventListener('fetch', event => {
if (event.request.mode === 'navigate') {
event.respondWith(fetch(event.request).catch(() => caches.match('/')));
}
});
اگر Python 3 نصب داری، از داخل پوشهٔ pwa-check این دستور ترمینال را اجرا کن و http://localhost:8000 را باز کن:
python3 -m http.server 8000
یکبار صفحه را آنلاین باز کن، سپس در ابزار توسعهٔ مرورگر به بخش Application و Service Workers برو و ثبت شدن sw.js را بررسی کن. بعد از فعال شدن آن، حالت Offline را در ابزار شبکه روشن و صفحه را تازهسازی کن؛ باید همان صفحهٔ آزمایشی را ببینی. برای بررسی نصبپذیری اپ اصلی، manifest و آیکونهای مناسب را آماده کن و نسخهٔ عمومی را روی HTTPS آزمایش کن؛ localhost استثنای محیط توسعه است. نمایش گزینهٔ نصب یا «افزودن به صفحهٔ اصلی» به مرورگر و شرایط آن بستگی دارد. این آزمایش محلی را با اثبات نصبپذیری اپ اصلی اشتباه نگیر.
۸. باگهای service worker و صف صوت را جداگانه پیدا کن
service worker میتواند فایل قدیمی را نگه دارد و باعث شود پس از تغییر کد، همچنان صفحهٔ قبلی یا رفتاری عجیب ببینی. در پروژهٔ نمونه، هنگام برگشت به اجرای محلی، صفحه درست بارگذاری نمیشد و بررسی Application → Service Workers و گزینهٔ Unregister، همراه با پاکسازی دادهٔ سایت، بخشی از عیبیابی بود. این کار را فقط برای مبدأ آزمایشی انجام بده: Clear site data ممکن است صف صوت و دادهٔ محلی همان مبدأ را هم حذف کند.
برای عیبیابی، ابتدا نشانی و پورت را تأیید کن. بعد در Console خطاها، در Network درخواست ناموفق و در Application وضعیت service worker و ذخیرهسازی را ببین. اگر پس از انتشار، رابط محلی تعداد موارد صف را نشان میدهد ولی نسخهٔ آنلاین نه، صرفِ باز شدن صفحه کافی نیست؛ روی همان نسخهٔ آنلاین یک صوت تازه ضبط کن، صفحه را تازهسازی کن و ببین مورد هنوز در صف هست یا خیر. صفِ localhost، صفِ دامنهٔ منتشرشده و صفِ گوشی دیگر، ذخیرهسازی محلیِ یکسانی نیستند؛ برای جابهجایی یا همگامسازی آنها قابلیت جداگانه لازم است.
سپس ارسال صف را با اینترنت پایدار امتحان کن. هر مورد باید نتیجهٔ قابلفهم داشته باشد؛ نمایش متنی مثل object Object بهجای گزارش، نشانهٔ درست نبودن نمایش نتیجه است، نه موفقیت پردازش. اگر پردازش خطا خورد، مورد صوتی را بدون تأیید پاک نکن و تکرار ارسال را طوری طراحی کن که گزارش تکراری ناخواسته نسازد. بهتر است هر اصلاح را ابتدا در اجرای محلی بسنجی، بعد خروجی جدید را منتشر و همان مسیر را دوباره روی لینک عمومی تکرار کنی.
۹. تحویل نهایی را روی دستگاهی غیر از دستگاه توسعه بسنج
حالت نمایش موبایل در ابزار توسعه برای پیدا کردن ایراد چیدمان مفید است، اما جای گوشی واقعی را نمیگیرد. لینک منتشرشده را روی گوشی دیگری و ترجیحاً با اینترنتی غیر از شبکهٔ کامپیوتر توسعه باز کن. برای آزمون میکروفون، از نشانی عمومیِ HTTPS استفاده کن: http://localhost روی همان دستگاه استثنای توسعه است، اما باز شدن اپ از طریق http://IP روی گوشی به معنی در دسترس بودن مجوز میکروفون نیست. از آغاز تا پایان پیش برو: صفحه باز شود، ورود یا اتصال حساب طبق انتظار انجام شود، اجازهٔ میکروفون درخواست شود، صدا وارد صف شود، تازهسازی صفحه صف را حذف نکند و پس از ارسال، گزارش پردازششده در جای موردانتظار دیده شود. سپس یکبار قطع اینترنت و تلاش دوباره را امتحان کن.
تحویل واقعی تو در پایان این تمرین فقط یک URL نیست: یک لینک قابلبازشدن، یک commit از نسخهٔ آزمایششده، و یادداشتی کوتاه از نتیجهٔ آزمون روی دستگاه دوم داشته باش. در یادداشت مشخص کن کدام بخشها بدون اینترنت کار میکنند، دادهٔ صوتی تا پیش از ارسال کجا میماند، و چه چیزی هنوز نیازمند بکاند یا کنترل دسترسی بهتر است. اگر این سه مورد را با اطمینان نمیتوانی توضیح بدهی، هنوز زود است اپ را «آمادهٔ استفادهٔ دیگران» بدانی.
مطالعهٔ مرتبط
گیت برای وایب کدینگ؛ چطور تغییرات هوش مصنوعی را کنترل و بازیابی کنیم
ویدیوی کامل
اگر میخواهی روند کار و آزمونها را هم ببینی، ویدیوی کامل این آموزش اینجاست:


دیدگاهتان را بنویسید
برای نوشتن دیدگاه باید وارد بشوید.