الفرق بين المراجعتين لصفحة: «Node.js/esm»
جميل-بيلوني (نقاش | مساهمات) طلا ملخص تعديل |
ط استبدال النص - '\[\[تصنيف:(.*)\]\]' ب'{{SUBPAGENAME}}' |
||
سطر 181: | سطر 181: | ||
== مصادر == | == مصادر == | ||
* [https://nodejs.org/dist/latest-v10.x/docs/api/esm.html صفحة 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).