Skip to content

تطبيقات قابلة للتنفيذ المفردة

[السجل]

الإصدارالتغييرات
v20.6.0تمت إضافة دعم لـ "useSnapshot".
v20.6.0تمت إضافة دعم لـ "useCodeCache".
v19.7.0, v18.16.0تمت الإضافة في: v19.7.0, v18.16.0

[مستقر: 1 - تجريبي]

مستقر: 1 الثبات: 1.1 - تطوير نشط

رمز المصدر: src/node_sea.cc

تتيح هذه الميزة توزيع تطبيق Node.js بسهولة على نظام ليس به Node.js مثبت.

يدعم Node.js إنشاء تطبيقات قابلة للتنفيذ المفردة من خلال السماح بحقن كتلة تم إعدادها بواسطة Node.js، والتي يمكن أن تحتوي على برنامج نصي مجمع، في ملف node الثنائي. أثناء بدء التشغيل، يتحقق البرنامج مما إذا كان هناك أي شيء قد تم حقنه. إذا تم العثور على الكتلة، فإنه ينفذ البرنامج النصي الموجود في الكتلة. بخلاف ذلك، يعمل Node.js كما هو معتاد.

لا تدعم ميزة التطبيق القابل للتنفيذ المفرد حاليًا إلا تشغيل برنامج نصي مضمن واحد باستخدام نظام الوحدات CommonJS.

يمكن للمستخدمين إنشاء تطبيق قابل للتنفيذ مفرد من البرنامج النصي المجمع الخاص بهم باستخدام ملف node الثنائي نفسه وأي أداة يمكنها حقن الموارد في الملف الثنائي.

فيما يلي الخطوات لإنشاء تطبيق قابل للتنفيذ مفرد باستخدام إحدى هذه الأدوات، postject:

إنشاء كتل إعداد التطبيقات القابلة للتنفيذ المفردة

يمكن إنشاء كتل إعداد التطبيقات القابلة للتنفيذ المفردة التي يتم حقنها في التطبيق باستخدام علم --experimental-sea-config من ملف Node.js الثنائي الذي سيتم استخدامه لبناء التطبيق القابل للتنفيذ المفرد. يأخذ مسارًا إلى ملف تكوين بتنسيق JSON. إذا لم يكن المسار الممرر إليه مطلقًا، فسيستخدم Node.js المسار النسبي لمسار العمل الحالي.

يقرأ التكوين حاليًا الحقول الرئيسية التالية:

json
{
  "main": "/path/to/bundled/script.js",
  "output": "/path/to/write/the/generated/blob.blob",
  "disableExperimentalSEAWarning": true, // الافتراضي: false
  "useSnapshot": false, // الافتراضي: false
  "useCodeCache": true, // الافتراضي: false
  "assets": {
    // اختياري
    "a.dat": "/path/to/a.dat",
    "b.txt": "/path/to/b.txt"
  }
}

إذا لم تكن المسارات مطلقة، فسيستخدم Node.js المسار النسبي لمسار العمل الحالي. يجب أن يكون إصدار ملف Node.js الثنائي المستخدم لإنتاج الكتلة هو نفسه الإصدار الذي سيتم حقن الكتلة فيه.

ملاحظة: عند إنشاء تطبيقات SEA متعددة المنصات (مثل إنشاء SEA لـ linux-x64 على darwin-arm64)، يجب تعيين useCodeCache و useSnapshot على false لتجنب إنشاء ملفات قابلة للتنفيذ غير متوافقة. نظرًا لأن ذاكرة التخزين المؤقت للرمز واللقطات لا يمكن تحميلها إلا على نفس النظام الأساسي الذي تم تجميعها فيه، فقد يتعطل الملف القابل للتنفيذ الناتج عند بدء التشغيل عند محاولة تحميل ذاكرة التخزين المؤقت للرمز أو اللقطات التي تم إنشاؤها على نظام أساسي مختلف.

الأصول

يمكن للمستخدمين تضمين الأصول عن طريق إضافة قاموس مسار مفتاح إلى التكوين كحقل assets. في وقت البناء، سيقوم Node.js بقراءة الأصول من المسارات المحددة وحزمها في كتلة التحضير. في الملف التنفيذي المُولّد، يمكن للمستخدمين استرداد الأصول باستخدام واجهات برمجة التطبيقات sea.getAsset() وsea.getAssetAsBlob().

json
{
  "main": "/path/to/bundled/script.js",
  "output": "/path/to/write/the/generated/blob.blob",
  "assets": {
    "a.jpg": "/path/to/a.jpg",
    "b.txt": "/path/to/b.txt"
  }
}

يمكن لتطبيق الملف التنفيذي الوحيد الوصول إلى الأصول على النحو التالي:

js
const { getAsset, getAssetAsBlob, getRawAsset } = require('node:sea')
// تُرجع نسخة من البيانات في ArrayBuffer.
const image = getAsset('a.jpg')
// تُرجع سلسلة مُشفّرة من الأصل كـ UTF8.
const text = getAsset('b.txt', 'utf8')
// تُرجع Blob يحتوي على الأصل.
const blob = getAssetAsBlob('a.jpg')
// تُرجع ArrayBuffer يحتوي على الأصل الخام بدون نسخ.
const raw = getRawAsset('a.jpg')

راجع وثائق واجهات برمجة التطبيقات sea.getAsset() وsea.getAssetAsBlob() وsea.getRawAsset() لمزيد من المعلومات.

دعم لقطة بدء التشغيل

يمكن استخدام حقل useSnapshot لتمكين دعم لقطة بدء التشغيل. في هذه الحالة، لن يتم تشغيل البرنامج النصي main عند تشغيل الملف التنفيذي النهائي. بدلاً من ذلك، سيتم تشغيله عند توليد كتلة تحضير تطبيق الملف التنفيذي الوحيد على جهاز البناء. ستتضمن كتلة التحضير المُولّدة حينها لقطة تُسجّل الحالات التي تم تهيئتها بواسطة البرنامج النصي main. سيقوم الملف التنفيذي النهائي مع كتلة التحضير المُحقونة بفكّ تسلسل اللقطة في وقت التشغيل.

عندما تكون قيمة useSnapshot صحيحة، يجب أن يقوم البرنامج النصي الرئيسي باستدعاء واجهة برمجة التطبيقات v8.startupSnapshot.setDeserializeMainFunction() لتهيئة الكود الذي يجب تشغيله عند تشغيل الملف التنفيذي النهائي بواسطة المستخدمين.

النمط النموذجي لتطبيق لاستخدام اللقطة في تطبيق ملف تنفيذي واحد هو:

تُطبّق القيود العامة لبرامج نصوص لقطة بدء التشغيل أيضًا على البرنامج النصي الرئيسي عندما يتم استخدامه لبناء لقطة لتطبيق الملف التنفيذي الوحيد، ويمكن للبرنامج النصي الرئيسي استخدام واجهة برمجة التطبيقات v8.startupSnapshot للتكيّف مع هذه القيود. راجع الوثائق حول دعم لقطة بدء التشغيل في Node.js.

دعم ذاكرة التخزين المؤقت لرمز V8

عندما يتم تعيين useCodeCache إلى true في التكوين، أثناء إنشاء كتلة التحضير القابلة للتنفيذ المفردة، سيقوم Node.js بتجميع البرنامج النصي main لإنشاء ذاكرة التخزين المؤقت لرمز V8. ستكون ذاكرة التخزين المؤقت للرمز المُولدة جزءًا من كتلة التحضير وسيتم حقنها في الملف القابل للتنفيذ النهائي. عند تشغيل تطبيق قابل للتنفيذ واحد، بدلاً من تجميع البرنامج النصي main من الصفر، سيستخدم Node.js ذاكرة التخزين المؤقت للرمز لتسريع عملية التجميع، ثم ينفذ البرنامج النصي، مما يحسن أداء بدء التشغيل.

ملاحظة: لا يعمل import() عندما يكون useCodeCache مساويًا لـ true.

في البرنامج النصي الرئيسي المُحقن

واجهة برمجة تطبيقات التطبيق القابل للتنفيذ المفرد

يسمح المُدمج node:sea بالتفاعل مع تطبيق قابل للتنفيذ واحد من البرنامج النصي الرئيسي لـ JavaScript المضمن في الملف القابل للتنفيذ.

sea.isSea()

مضاف في: v21.7.0، v20.12.0

  • المُرجَع: <boolean> ما إذا كان هذا البرنامج النصي قيد التشغيل داخل تطبيق قابل للتنفيذ واحد.

sea.getAsset(key[, encoding])

مضاف في: v21.7.0، v20.12.0

يمكن استخدام هذه الطريقة لاسترداد الأصول المُهيأة ليتم تجميعها في تطبيق قابل للتنفيذ واحد في وقت البناء. يتم إرسال خطأ عندما لا يمكن العثور على أي أصل مطابق.

  • key <string> مفتاح الأصل في القاموس الذي حدده حقل assets في تكوين تطبيق قابل للتنفيذ واحد.
  • encoding <string> إذا تم تحديده، فسيتم فك ترميز الأصل كسلسلة. يتم قبول أي ترميز يدعمه TextDecoder. إذا لم يتم تحديده، فسيتم إرجاع ArrayBuffer يحتوي على نسخة من الأصل بدلاً من ذلك.
  • المُرجَع: <string> | <ArrayBuffer>

sea.getAssetAsBlob(key[, options])

مضاف في: v21.7.0، v20.12.0

يشبه sea.getAsset() ، ولكنه يُرجع النتيجة في Blob. يتم رمي خطأ عندما لا يمكن العثور على أصل مطابق.

  • key <string> مفتاح الأصل في القاموس المحدد بواسطة حقل assets في تكوين تطبيق التنفيذ الأحادي.

  • options <Object>

    • type <string> نوع MIME اختياري للـ blob.
  • المُرجَع: <Blob>

sea.getRawAsset(key)

مضاف في: v21.7.0، v20.12.0

يمكن استخدام هذه الطريقة لاسترداد الأصول المُهيأة لتضمينها في تطبيق التنفيذ الأحادي في وقت البناء. يتم رمي خطأ عندما لا يمكن العثور على أصل مطابق.

على عكس sea.getAsset() أو sea.getAssetAsBlob()، هذه الطريقة لا تُرجع نسخة. بدلاً من ذلك، تُرجع الأصل الخام المُضمن داخل الملف التنفيذي.

في الوقت الحالي، يجب على المستخدمين تجنب الكتابة في مُخزن مُصفوفات المُرجع المُرجع. إذا لم يتم وضع علامة على القسم المُحقن على أنه قابل للكتابة أو لم يتم محاذاته بشكل صحيح، فإن الكتابة في مُخزن مُصفوفات المُرجع المُرجع من المحتمل أن تؤدي إلى تعطل.

  • key <string> مفتاح الأصل في القاموس المحدد بواسطة حقل assets في تكوين تطبيق التنفيذ الأحادي.
  • المُرجَع: <ArrayBuffer>

require(id) في البرنامج النصي الرئيسي المُحقن ليس قائمًا على الملفات

require() في البرنامج النصي الرئيسي المُحقن ليس هو نفسه require() المتوفر للنُظم المُستقلة التي لم يتم حقنها. كما أنه لا يمتلك أيًا من الخصائص التي لا يمتلكها require() غير المُحقن باستثناء require.main. لا يمكن استخدامه إلا لتحميل النُظم المُدمجة. ستؤدي محاولة تحميل وحدة لا يمكن العثور عليها إلا في نظام الملفات إلى رمي خطأ.

بدلاً من الاعتماد على require() القائم على الملفات، يمكن للمستخدمين تجميع تطبيقاتهم في ملف JavaScript مستقل لحقنه في الملف التنفيذي. وهذا يضمن أيضًا رسم بياني للبُنية التابعة أكثر تحديدًا.

ومع ذلك، إذا كانت هناك حاجة إلى require() القائم على الملفات، فيمكن تحقيق ذلك أيضًا:

js
const { createRequire } = require('node:module')
require = createRequire(__filename)

__filename و module.filename في البرنامج النصي الرئيسي المُدمج

قيم __filename و module.filename في البرنامج النصي الرئيسي المُدمج تساوي process.execPath.

__dirname في البرنامج النصي الرئيسي المُدمج

قيمة __dirname في البرنامج النصي الرئيسي المُدمج تساوي اسم الدليل الخاص بـ process.execPath.

ملاحظات

عملية إنشاء تطبيق قابل للتنفيذ المفرد

يجب أن تقوم الأداة التي تهدف إلى إنشاء تطبيق Node.js قابل للتنفيذ المفرد بحقن محتويات الكتلة المُعدّة باستخدام --experimental-sea-config" في:

  • مورد مُسمّى NODE_SEA_BLOB إذا كان ملف node الثنائي ملفًا من نوع PE
  • قسم مُسمّى NODE_SEA_BLOB في مقطع NODE_SEA إذا كان ملف node الثنائي ملفًا من نوع Mach-O
  • ملاحظة مُسمّاة NODE_SEA_BLOB إذا كان ملف node الثنائي ملفًا من نوع ELF

ابحث في الملف الثنائي عن سلسلة NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2:0 fuse وقلب الحرف الأخير إلى 1 للإشارة إلى أنه تم حقن مورد.

دعم النظام الأساسي

يُختبر دعم التطبيقات القابلة للتنفيذ المفرد بانتظام على CI فقط على الأنظمة الأساسية التالية:

وذلك لعدم وجود أدوات أفضل لإنشاء تطبيقات قابلة للتنفيذ المفرد يمكن استخدامها لاختبار هذه الميزة على أنظمة أساسية أخرى.

نقترح أدوات/مسارات عمل أخرى لحقن الموارد. يُرجى بدء مناقشة في https://github.com/nodejs/single-executable/discussions لمساعدتنا في توثيقها.