Bugsy يشرح
متغيّرات البيئة وملف .env
كيف يتصل البناء نفسه بـ localhost على حاسوبك وبالواجهة البرمجية الحقيقية في الإنتاج، وأي مصدر يفوز حين يُضبط المتغيّر مرتين، ولماذا لا تحمل الأسرار البادئة NEXT_PUBLIC_ أبدًا.
7 دقائق لعبة واحدة
- DevOps
- الأدوات
- الأمان
على حاسوبك، يتصل تطبيقك بواجهة برمجية (API) على العنوان http://localhost:4000. وفي الإنتاج (production)، تتصل الشيفرة نفسها تمامًا بالعنوان https://api.example.com. ولا أحد يعدّل الشيفرة بين الحالتين. فمن أين تعرف الشيفرة أي عنوان تستخدم؟
من بيئتها (environment): مجموعة صغيرة من الإعدادات تُسلَّم إلى البرنامج حين يبدأ، من خارج الشيفرة.
ما هو متغيّر البيئة؟
كل برنامج يعمل يتسلّم قائمة من الأزواج NAME=value ممن شغّله. هذه القائمة هي بيئته. ولواجهة الأوامر (shell) في الطرفية بيئة خاصة بها، وكل برنامج تشغّله منها يأخذ نسخة منها.
ويعرض Node.js هذه القائمة في process.env. فقراءة process.env.API_URL تعطيك القيمة نصًّا (string)، أو undefined إن لم يضبطها أحد.
export API_URL=https://staging.example.comnode -e "console.log(process.env.API_URL)"
يضيف export المتغيّر API_URL إلى بيئة الطرفية، فيرثه node الذي يبدأ في السطر التالي ويطبع https://staging.example.com. أما كتابة API_URL=https://staging.example.com npm run dev فتضبطه لذلك الأمر وحده.
لماذا تعيش الإعدادات خارج الشيفرة؟
الإعدادات (config) هي كل ما يتغيّر بين الأماكن التي يعمل فيها التطبيق: عناوين الواجهات البرمجية، وكلمات مرور قواعد البيانات، ومفاتيح API. أما الشيفرة فهي ما يبقى ثابتًا. وتلخّص إرشادات تطبيق العوامل الاثني عشر (twelve-factor app) الأمر هكذا: ضع الإعدادات في البيئة، لا في الشيفرة.
عندها يعمل البناء نفسه على حاسوبك وعلى خادم الاختبار وفي الإنتاج، ولكلٍّ إعداداته. ولا تصل كلمات المرور إلى الشيفرة أبدًا. وهذا اختبار جيد: هل تستطيع نشر شيفرتك اليوم دون أن تسرّب أي بيانات دخول؟
ملفات .env، ومن يفوز
كتابة export لكل متغيّر أمر مُتعب، لذا تقرأ الأدوات المتغيّرات من ملف اسمه .env، بزوج NAME=value في كل سطر. ويحمّل Next.js هذه الملفات تلقائيًا. أما Node.js وحده فيستطيع ذلك بالأمر node --env-file=.env (من الإصدار Node 20.6) أو بالحزمة dotenv.
وحين يُضبط الاسم نفسه في أكثر من مكان، يفحص Next.js المصادر بترتيب ثابت، وأول مصدر يجده يفوز. في وضع التطوير يكون الترتيب من الأقوى إلى الأضعف: البيئة الحقيقية (من الطرفية، أو من إعدادات الاستضافة)، ثم `.env.development.local`، ثم `.env.local`، ثم `.env.development`، ثم `.env`. فالملف لا يكتب أبدًا فوق متغيّر مضبوط من قبل، وهكذا تتصرف dotenv افتراضيًا أيضًا.
أما بناء الإنتاج فيقرأ .env.production.local و.env.production بدلًا من ملفات التطوير. والقاعدة هي نفسها: ملف .local يتغلّب على نظيره المشترك، والبيئة الحقيقية تتغلّب على كل الملفات. وهناك استثناء واحد: يُتخطّى .env.local أثناء الاختبارات (حين تكون قيمة NODE_ENV هي test)، لتحصل الاختبارات على القيم نفسها على كل جهاز.
شيفرة الخادم وشيفرة المتصفح
شيفرة الخادم، مثل مسارات API ومكوّنات الخادم (server components)، تعمل على جهاز تتحكم فيه، لذا تستطيع قراءة كل المتغيّرات. أما شيفرة المتصفح فتعمل على أجهزة زوّارك، ولا يعطيها Next.js إلا المتغيّرات التي تبدأ أسماؤها بالبادئة NEXT_PUBLIC_.
ولكي يفعل ذلك، يستبدل Next.js بالعبارة process.env.NEXT_PUBLIC_API_URL في شيفرة JavaScript الخاصة بالمتصفح القيمةَ نفسها، وقت البناء. فتصير القيمة علنية: يستطيع أي أحد أن يفتح شيفرة JavaScript التي نزّلها ويقرأها. وتغييرها لاحقًا يحتاج بناءً جديدًا.
جرّب: شغّل المصادر وأطفئها لترى من يفوز، وأطفئها كلها، ثم أضف البادئة.
جرّب
اختبار سريع
أودِع المثال، وتجاهل الملف الحقيقي
يحمل .env.local قيمك الحقيقية، وبعضها أسرار. وكل ما تودعه في git يبقى في سجلّه (history) حتى لو حذفت الملف، ويستطيع قراءته كل من يصل إلى المستودع (repository). لذا تُكتب ملفات env في .gitignore، وهو قائمة الملفات التي لا يتتبعها git أبدًا.
وبدلًا منها أودِع ملف .env.example: الأسماء نفسها بقيم مؤقتة، مثل API_URL=http://localhost:4000 أو STRIPE_SECRET_KEY=. فينسخه الزميل الجديد إلى .env.local ويملأ القيم. وهكذا يوثّق ما يحتاجه التطبيق دون أن يسرّب شيئًا.
اختبار سريع
سؤال الزعيم
اجمع كل ما تعلمته.
اختبار سريع
انتهيت من القراءة؟
حلّ 3 اختبارات سريعة بعد لتنهي.