الفرق بين المراجعتين لصفحة: «Node.js/esm»
جميل-بيلوني (نقاش | مساهمات) إضافة محتويات الصفحة. |
ط استبدال النص - '\[\[تصنيف:(.*)\]\]' ب'{{SUBPAGENAME}}' |
||
(مراجعة متوسطة واحدة بواسطة مستخدم واحد آخر غير معروضة) | |||
سطر 1: | سطر 1: | ||
<noinclude>{{DISPLAYTITLE:وحدات ECMAScript في Node.js}}</noinclude> | <noinclude>{{DISPLAYTITLE:وحدات ECMAScript في Node.js}}</noinclude> | ||
الاستقرار: 1-قيد التجريب | الاستقرار: 1-قيد التجريب | ||
تحوي Node.js دعمًا لوحدات ES اعتمادًا على Node.js EP من أجل وحدات ES. | تحوي Node.js دعمًا لوحدات ES اعتمادًا على Node.js EP من أجل وحدات ES. | ||
ليست جميع مزايا EP كاملةً بعد، وستُحضَر | |||
ليست جميع مزايا EP كاملةً بعد، وستُحضَر كدعمٍ وتنفيذٍ من أجل VM عندما يكون جاهزًا. لا تزال رسائل الخطأ في طور التحسين والتطوير. | |||
== عملية التفعيل == | == عملية التفعيل == | ||
يمكن استعمال الراية <code>--experimental-modules</code> لتفعيل المزايا التي تمكن من تحميل وحدات ESM. متى ما ضُبِط ذلك، يمكن تحميل الملفات التي تنتهي باللاحقة <code>.mjs</code> كوحدات ES. | يمكن استعمال الراية <code>--experimental-modules</code> لتفعيل المزايا التي تمكن من تحميل وحدات ESM. متى ما ضُبِط ذلك، يمكن تحميل الملفات التي تنتهي باللاحقة <code>.mjs</code> كوحدات ES. | ||
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
node --experimental-modules my-app.mjs | node --experimental-modules my-app.mjs | ||
سطر 10: | سطر 12: | ||
== المزايا == | == المزايا == | ||
=== المزايا المدعومة === | === المزايا المدعومة === | ||
يمكن أن يكون الوسيط CLI لنقطة الإدخال الرئيسية للبرنامج نقطةَ إدخالٍ لمخطط ESM فقط. يمكن استعمال الاستيراد الديناميكي (dynamic import) أيضًا لإنشاء نُقط إدخال إلى مخططات ESM في وقت التشغيل (runtime). | يمكن أن يكون الوسيط <code>CLI</code> لنقطة الإدخال الرئيسية للبرنامج نقطةَ إدخالٍ لمخطط ESM فقط. يمكن استعمال الاستيراد الديناميكي (dynamic import) أيضًا لإنشاء نُقط إدخال إلى مخططات ESM في وقت التشغيل (runtime). | ||
==== <code>import.meta</code> ==== | ==== <code>import.meta</code> ==== | ||
* <Object> | * [[JavaScript/Object|<Object>]] | ||
الخاصية <code>import.meta</code> الوصفية (metaproperty) هي كائن <code>Object</code> يحتوي على الخاصية التالية: | الخاصية <code>import.meta</code> الوصفية (metaproperty) هي كائن <code>[[JavaScript/Object|Object]]</code> يحتوي على الخاصية التالية: | ||
* <code>url</code>: <string> العنوان <code>file:</code> URLللوحدة. | * <code>url</code>: [[JavaScript/String|<string>]] العنوان <code>file:</code> URLللوحدة. | ||
=== المزايا غير المدعومة === | === المزايا غير المدعومة === | ||
{| class="wikitable" | |||
المزيَّة | !المزيَّة | ||
السبب | !السبب | ||
<code>require('./foo.mjs')</code> | |- | ||
إن لوحدات ES دقة وتوقيت مختلف، إذ تستعمل الاستيراد الديناميكي (dynamic import). | |<code>require('./foo.mjs')</code> | ||
|إن لوحدات ES دقة وتوقيت مختلف، إذ تستعمل الاستيراد الديناميكي (dynamic import). | |||
|} | |||
== أبرز الاختلافات بين «الاستيراد» (import) و «الطلب» (require) == | == أبرز الاختلافات بين «الاستيراد» (import) و «الطلب» (require) == | ||
سطر 30: | سطر 34: | ||
لا يُستعمَل <code>require.cache</code> من قِبَل <code>import</code>، إذ لديه ذاكرة مخبئية منفصلة. | لا يُستعمَل <code>require.cache</code> من قِبَل <code>import</code>، إذ لديه ذاكرة مخبئية منفصلة. | ||
=== العنوان URL المعتمد على المسارات === | === العنوان URL المعتمد على المسارات === | ||
تُستبيَن ESM وتخزَّن اعتمادًا على دلالات العنوان URL. هذا يعني أنَّ الملفات تحتوي على محارف خاصية مثل <code>#</code> و <code>?</code> وتحتاج إلى تهريب. | تُستبيَن ESM وتخزَّن اعتمادًا على دلالات العنوان [https://url.spec.whatwg.org/ URL]. هذا يعني أنَّ الملفات تحتوي على محارف خاصية مثل <code>#</code> و <code>?</code> وتحتاج إلى تهريب. | ||
ستُحمَّل الوحدات عدة مرات إن كان المحدد <code>import</code> المستعمل لاستبيانها يملك استعلامًا (query) أو قطعةً (fragment) مختلفةً. | ستُحمَّل الوحدات عدة مرات إن كان المحدد <code>import</code> المستعمل لاستبيانها يملك استعلامًا (query) أو قطعةً (fragment) مختلفةً. | ||
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
سطر 39: | سطر 44: | ||
== التشغيل المتداخل مع الوحدات الموجودة (Interop with existing modules) == | == التشغيل المتداخل مع الوحدات الموجودة (Interop with existing modules) == | ||
يمكن استعمال الوحدات CommonJS، و JSON، و C++ جميعها مع <code>import</code>. | يمكن استعمال الوحدات CommonJS، و JSON، و C++ جميعها مع <code>import</code>. | ||
الوحدات التي تحمَّل بهذه الطريقة ستُحمَّل مرةً واحدةً فقط حتى إن اختلفت | |||
الوحدات التي تحمَّل بهذه الطريقة ستُحمَّل مرةً واحدةً فقط حتى إن اختلفت سَلسَلتها النصية التي تمثِّل الاستعلام أو القطعة بين العبارات <code>improt</code>. | |||
عند التحميل عبر <code>import</code>، ستوفر هذه الوحدات تصديرًا وحيدًا من أجل <code>default</code> يمثل قيمة <code>module.exports</code> في الوقت الذي تُنهِي فيه التقييم. | عند التحميل عبر <code>import</code>، ستوفر هذه الوحدات تصديرًا وحيدًا من أجل <code>default</code> يمثل قيمة <code>module.exports</code> في الوقت الذي تُنهِي فيه التقييم. | ||
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
سطر 49: | سطر 56: | ||
foo.one === 1; // true | foo.one === 1; // true | ||
</syntaxhighlight> | </syntaxhighlight> | ||
ستوفِّر الوحدات المضمَّنة تصديرات مسماة (named exports) لواجهاتها البرمجية العامة بالإضافة إلى تصديرٍ افتراضيٍّ يمكن استعماله من أجل عدة أشياء أهمها تعديل التصديرات المسماة. تُحدَّث التصديرات المسماة للوحدات المضمَّنة عندما يتم الوصول إلى خاصية التصديرات المقابلة أو إعادة تعريفها أو حذفها. | ستوفِّر الوحدات المضمَّنة تصديرات مسماة (named exports) لواجهاتها البرمجية العامة بالإضافة إلى تصديرٍ افتراضيٍّ يمكن استعماله من أجل عدة أشياء أهمها تعديل التصديرات المسماة. تُحدَّث التصديرات المسماة للوحدات المضمَّنة عندما يتم الوصول إلى خاصية التصديرات المقابلة أو إعادة تعريفها أو حذفها.<syntaxhighlight lang="javascript"> | ||
<syntaxhighlight lang="javascript"> | |||
import EventEmitter from 'events'; | import EventEmitter from 'events'; | ||
const e = new EventEmitter(); | const e = new EventEmitter(); | ||
< | </syntaxhighlight> | ||
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
import { readFile } from 'fs'; | import { readFile } from 'fs'; | ||
سطر 72: | سطر 78: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== خطافات المحمِّل (Loader hooks) == | == خطافات المحمِّل (Loader hooks) == | ||
إن أردت تخصيص الدقة الافتراضية للوحدة، فيمكن تمرير خطافات المحمِّل اختياريًّا عبر الوسيط <code>--loader ./loader-name.mjs</code> إلى Node.js. | إن أردت تخصيص الدقة الافتراضية للوحدة، فيمكن تمرير خطافات المحمِّل اختياريًّا عبر الوسيط <code>--loader ./loader-name.mjs</code> إلى Node.js. | ||
عندما تُستعمَل الخطافات، فإنّها تُطبَّق على محمِّل الوحدة ES فقط وليس على أي محمِّل لوحدات CommonJS | عندما تُستعمَل الخطافات، فإنّها تُطبَّق على محمِّل الوحدة ES فقط وليس على أي محمِّل لوحدات CommonJS | ||
=== الخطاف <code>resolve</code> === | === الخطاف <code>resolve</code> === | ||
سطر 90: | سطر 97: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
يُعطَى <code>parentModuleURL</code> على أنَّه <code>undefined</code> عند إجراء عملية تحميل Node.js الرئيسية نفسها. | يُعطَى <code>parentModuleURL</code> على أنَّه <code>undefined</code> عند إجراء عملية تحميل Node.js الرئيسية نفسها. | ||
تمرَّر دالة دقة الوحدة Node.js ES الافتراضية كوسيط ثالث إلى المستبين من أجل سهولة توافق تدفقات العمل. | تمرَّر دالة دقة الوحدة Node.js ES الافتراضية كوسيط ثالث إلى المستبين من أجل سهولة توافق تدفقات العمل. | ||
بالإضافة إلى إعادة قيمة ملف عنوان URL المستبين، يعيد الخطاف <code>resolve</code> الخاصية <code>format</code> أيضًا التي تحدد صيغة الوحدة للوحدة المستبينة. يمكن أن تأخذ هذه الخاصية إحدى القيم التالية: | بالإضافة إلى إعادة قيمة ملف عنوان URL المستبين، يعيد الخطاف <code>resolve</code> الخاصية <code>format</code> أيضًا التي تحدد صيغة الوحدة للوحدة المستبينة. يمكن أن تأخذ هذه الخاصية إحدى القيم التالية: | ||
{| class="wikitable" | |||
format | !<code>format</code> | ||
الوصف | !الوصف | ||
'esm' | |- | ||
تحميل الوحدة JavaScript القياسية. | |<code>'esm'</code> | ||
'cjs' | |تحميل الوحدة JavaScript القياسية. | ||
تحميل الوحدة CommonJS بنمط node-style. | |- | ||
'builtin' | |<code>'cjs'</code> | ||
تحميل الوحدة CommonJS المضمَّنة في node. | |تحميل الوحدة CommonJS بنمط node-style. | ||
'json' | |- | ||
تحميل الملف JSON. | |<code>'builtin'</code> | ||
'addon' | |تحميل الوحدة CommonJS المضمَّنة في node. | ||
تحميل الإضافة C++. | |- | ||
'dynamic' | |<code>'json'</code> | ||
استعمال الخطاف <code>instantiate</code> الديناميكي. | |تحميل الملف JSON. | ||
|- | |||
|<code>'addon'</code> | |||
|تحميل الإضافة C++. | |||
|- | |||
|<code>'dynamic'</code> | |||
|استعمال الخطاف <code>instantiate</code> الديناميكي. | |||
|} | |||
على سبيل المثال، يتقيد المُحمِّل الزائف (dummy loader) الذي يحمِّل JavaScritp بقواعد دقة المتصفح مع إمكانية كتابة الملف JS الملحق ووحدات Node.js المضمَّنة: | على سبيل المثال، يتقيد المُحمِّل الزائف (dummy loader) الذي يحمِّل JavaScritp بقواعد دقة المتصفح مع إمكانية كتابة الملف JS الملحق ووحدات Node.js المضمَّنة: | ||
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
سطر 163: | سطر 178: | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
ستُستدعَى الدالة <code>execute</code> مع قائمة تصديرات الوحدة التي أعطيت في المقدمة حينئذٍ عند نقطة محددة بدقة لترتيب تقييم الوحدة لتلك الوحدة في شجرة الاستيرادات (import tree). | |||
== مصادر == | == مصادر == | ||
* صفحة ESM في توثيق Node.js الرسمي. | * [https://nodejs.org/dist/latest-v10.x/docs/api/esm.html صفحة ESM في توثيق Node.js الرسمي.] | ||
[[تصنيف:Node.js]] | [[تصنيف:Node.js|{{SUBPAGENAME}}]] |
المراجعة الحالية بتاريخ 11:17، 23 أكتوبر 2018
الاستقرار: 1-قيد التجريب
تحوي Node.js دعمًا لوحدات ES اعتمادًا على Node.js EP من أجل وحدات ES.
ليست جميع مزايا EP كاملةً بعد، وستُحضَر كدعمٍ وتنفيذٍ من أجل VM عندما يكون جاهزًا. لا تزال رسائل الخطأ في طور التحسين والتطوير.
عملية التفعيل
يمكن استعمال الراية --experimental-modules
لتفعيل المزايا التي تمكن من تحميل وحدات ESM. متى ما ضُبِط ذلك، يمكن تحميل الملفات التي تنتهي باللاحقة .mjs
كوحدات ES.
node --experimental-modules my-app.mjs
المزايا
المزايا المدعومة
يمكن أن يكون الوسيط CLI
لنقطة الإدخال الرئيسية للبرنامج نقطةَ إدخالٍ لمخطط ESM فقط. يمكن استعمال الاستيراد الديناميكي (dynamic import) أيضًا لإنشاء نُقط إدخال إلى مخططات ESM في وقت التشغيل (runtime).
import.meta
الخاصية import.meta
الوصفية (metaproperty) هي كائن Object
يحتوي على الخاصية التالية:
url
: <string> العنوان file:
URLللوحدة.
المزايا غير المدعومة
المزيَّة | السبب |
---|---|
require('./foo.mjs')
|
إن لوحدات ES دقة وتوقيت مختلف، إذ تستعمل الاستيراد الديناميكي (dynamic import). |
أبرز الاختلافات بين «الاستيراد» (import) و «الطلب» (require)
لا يوجد NODE_PATH
ليس NODE_PATH
جزءًا من استبيان المحددات import
. استعمل رجاء الوصلات الرمزية إن كان هذا السلوك مرغوبًا ولا بأس به.
لا يوجد require.extensions
لا يُستعمَل require.extensions
من قبل import
. يتوقع أن خطافات المحمِّل (loader hooks) يمكن أن توفر تدفق العمل (workflow) هذا في المستقبل.
لا يوجد require.cache
لا يُستعمَل require.cache
من قِبَل import
، إذ لديه ذاكرة مخبئية منفصلة.
العنوان URL المعتمد على المسارات
تُستبيَن ESM وتخزَّن اعتمادًا على دلالات العنوان URL. هذا يعني أنَّ الملفات تحتوي على محارف خاصية مثل #
و ?
وتحتاج إلى تهريب.
ستُحمَّل الوحدات عدة مرات إن كان المحدد import
المستعمل لاستبيانها يملك استعلامًا (query) أو قطعةً (fragment) مختلفةً.
import './foo?query=1'; // loads ./foo with query of "?query=1"
import './foo?query=2'; // loads ./foo with query of "?query=2"
في الوقت الحالي، الوحدات التي تستعمل البروتوكول file:
يمكنها أن تتحمَّل فقط.
التشغيل المتداخل مع الوحدات الموجودة (Interop with existing modules)
يمكن استعمال الوحدات CommonJS، و JSON، و C++ جميعها مع import
.
الوحدات التي تحمَّل بهذه الطريقة ستُحمَّل مرةً واحدةً فقط حتى إن اختلفت سَلسَلتها النصية التي تمثِّل الاستعلام أو القطعة بين العبارات improt
.
عند التحميل عبر import
، ستوفر هذه الوحدات تصديرًا وحيدًا من أجل default
يمثل قيمة module.exports
في الوقت الذي تُنهِي فيه التقييم.
// foo.js
module.exports = { one: 1 };
// bar.js
import foo from './foo.js';
foo.one === 1; // true
ستوفِّر الوحدات المضمَّنة تصديرات مسماة (named exports) لواجهاتها البرمجية العامة بالإضافة إلى تصديرٍ افتراضيٍّ يمكن استعماله من أجل عدة أشياء أهمها تعديل التصديرات المسماة. تُحدَّث التصديرات المسماة للوحدات المضمَّنة عندما يتم الوصول إلى خاصية التصديرات المقابلة أو إعادة تعريفها أو حذفها.
import EventEmitter from 'events';
const e = new EventEmitter();
import { readFile } from 'fs';
readFile('./foo.txt', (err, source) => {
if (err) {
console.error(err);
} else {
console.log(source);
}
});
import fs, { readFileSync } from 'fs';
fs.readFileSync = () => Buffer.from('Hello, ESM');
fs.readFileSync === readFileSync;
خطافات المحمِّل (Loader hooks)
إن أردت تخصيص الدقة الافتراضية للوحدة، فيمكن تمرير خطافات المحمِّل اختياريًّا عبر الوسيط --loader ./loader-name.mjs
إلى Node.js.
عندما تُستعمَل الخطافات، فإنّها تُطبَّق على محمِّل الوحدة ES فقط وليس على أي محمِّل لوحدات CommonJS
الخطاف resolve
يعيد الخطاف resolve
ملف عنوان URL المستبين وصيغة الوحدة لمحدد الوحدة المعطاة وملف عنوان URL الأب:
const baseURL = new URL('file://');
baseURL.pathname = `${process.cwd()}/`;
export async function resolve(specifier,
parentModuleURL = baseURL,
defaultResolver) {
return {
url: new URL(specifier, parentModuleURL).href,
format: 'esm'
};
}
يُعطَى parentModuleURL
على أنَّه undefined
عند إجراء عملية تحميل Node.js الرئيسية نفسها.
تمرَّر دالة دقة الوحدة Node.js ES الافتراضية كوسيط ثالث إلى المستبين من أجل سهولة توافق تدفقات العمل.
بالإضافة إلى إعادة قيمة ملف عنوان URL المستبين، يعيد الخطاف resolve
الخاصية format
أيضًا التي تحدد صيغة الوحدة للوحدة المستبينة. يمكن أن تأخذ هذه الخاصية إحدى القيم التالية:
format
|
الوصف |
---|---|
'esm'
|
تحميل الوحدة JavaScript القياسية. |
'cjs'
|
تحميل الوحدة CommonJS بنمط node-style. |
'builtin'
|
تحميل الوحدة CommonJS المضمَّنة في node. |
'json'
|
تحميل الملف JSON. |
'addon'
|
تحميل الإضافة C++. |
'dynamic'
|
استعمال الخطاف instantiate الديناميكي.
|
على سبيل المثال، يتقيد المُحمِّل الزائف (dummy loader) الذي يحمِّل JavaScritp بقواعد دقة المتصفح مع إمكانية كتابة الملف JS الملحق ووحدات Node.js المضمَّنة:
import path from 'path';
import process from 'process';
import Module from 'module';
const builtins = Module.builtinModules;
const JS_EXTENSIONS = new Set(['.js', '.mjs']);
const baseURL = new URL('file://');
baseURL.pathname = `${process.cwd()}/`;
export function resolve(specifier, parentModuleURL = baseURL, defaultResolve) {
if (builtins.includes(specifier)) {
return {
url: specifier,
format: 'builtin'
};
}
if (/^\.{0,2}[/]/.test(specifier) !== true && !specifier.startsWith('file:')) {
// For node_modules support:
// return defaultResolve(specifier, parentModuleURL);
throw new Error(
`imports must begin with '/', './', or '../'; '${specifier}' does not`);
}
const resolved = new URL(specifier, parentModuleURL);
const ext = path.extname(resolved.pathname);
if (!JS_EXTENSIONS.has(ext)) {
throw new Error(
`Cannot load file with non-JavaScript file extension ${ext}.`);
}
return {
url: resolved.href,
format: 'esm'
};
}
مع هذا المحمِّل، يؤدي تشغيل:
NODE_OPTIONS='--experimental-modules --loader ./custom-loader.mjs' node x.js
إلى تحميل الوحدة x.js
كوحدة ES مع دعم الدقة النسبية (مع تخطي تحميل node_modules
في هذا المثال).
الخطاف dynamicInstantiate
الديناميكي
إن أردت إنشاء وحدة ديناميكية مخصَّصة لا تتطابق مع أيٍّ من تفسيرات format
الموجودة، فاستعمل الخطاف dynamicInstantiate
. يُستدعَى هذا الخطاف مع الوحدات التي تعيد format: 'dynamic'
من الخطاف resolve
فقط.
export async function dynamicInstantiate(url) {
return {
exports: ['customExportName'],
execute: (exports) => {
// اجلب واضبط الدوال المتوافرة للحجز المسبق لأسماء التصدير
exports.customExportName.set('value');
}
};
}
ستُستدعَى الدالة execute
مع قائمة تصديرات الوحدة التي أعطيت في المقدمة حينئذٍ عند نقطة محددة بدقة لترتيب تقييم الوحدة لتلك الوحدة في شجرة الاستيرادات (import tree).