وحدة التحميل التلقائي باستخدام الاستيراد الديناميكي

في الآونة الأخيرة ، تم الإعلان عن دعم وحدات ECMAScript في Node.js ، وظهر دعم الواردات الديناميكية في ES2020. في هذه المقالة ، سأتحدث عن تنفيذ الحالة الواضحة المتمثلة في استخدام عمليات الاستيراد الديناميكية - مع أسماء دليل غير معروفة مسبقًا.


غطاء


مشاكل


غالبًا ما ألاحظ بنية الدليل التالية تقريبًا في المشروعات:


$ tree . ├── modules │ ├── a │ │ └── index.ts │ ├── b │ │ └── index.ts │ └── c │ └── bobule.ts ├── index.ts └── package.json 

ومحتويات index.ts :


 import a from './modules/a'; import b from './modules/b'; import c from './modules/c/bobule.ts'; export default { module: a, dopule: b, bobule: c }; 

ثم في مكان ما في المستوى الأعلى يوجد فهرس آخر يستورد هذا المؤشر. ويستورد هذا المؤشر ...


أود أن أكتب شيئًا مثل index.ts ذي المستوى index.ts


 import modules from './modules/*/*' 

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


الواردات الديناميكية


الميزة الرئيسية لاستيراد الديناميكي عبر الاستاتيكي هي الشكل الوظيفي ، والذي يسمح بتحميل الوحدات حسب الحالة. إنه يعمل بهذه الطريقة:


 // module.ts export const a = 'i love hexlet' const b = { referral: 'hexlet.io/?ref=162475' } export default b // index.ts const module = await import('./module.ts') module.default // { referral: 'hexlet.io/?ref=162475' } module.a // 'i love hexlet' 

وفقًا لذلك ، بإضافة القليل من fs إلى هذا التصميم ، ستتيح لك الواردات الحيوية الحصول على جميع الملفات من الدلائل الفرعية من أي مستوى.


PHP مستوحاة


ليست فكرة التحميل التلقائي جديدة وتستخدم بنشاط في PHP ، لأسباب هندسية وتاريخية ، لكن لا شيء يمنعني من خلق صعوباتي الخاصة والتغلب عليها بطوليًا. لذلك ، حاولت إنشاء قسم التحميل التلقائي في package.json وإنشاء أداة تقرأ اسم الوحدة النمطية حسب المفتاح ، ومسار الملف من القيمة:


 //  package.json { "autoload": { "modules": ["modules", "*", "index.ts"] "bobules": ["*", "*", "bobule.ts"], } } 

في حالة استخدام typescipt ، هناك لحظة مزعجة مع حقيقة أن الامتدادات تتغير بعد بناء التطبيق وهناك أكثر من اثنين: ts|js|mjs|tsx حتى تتمكن من أخذ هذا في الاعتبار على الفور عن طريق سرد جميع الخيارات المتاحة ، وتنزيل فقط الخيارات التي تحتاج إليها:


 //  package.json { "autoload": { "modules": ["modules", "*", "index.ts|js"] "bobules": ["*", "*", "bobule.ts|js"], } } 

تطبيق


تم الحصول على الحالات التالية:


  1. f(projectRoot, ['modules', '*', 'index.js|ts'], moduleName = 'default') // قم بتحميل الوحدات النمطية في المسار المحدد بواسطة المستخدم
  2. f(projectRoot) / / تحميل وحدات من package.json ، يتم تمرير أسماء الوحدة النمطية (مفاتيح في قسم التحميل f(projectRoot) في هذه الحالة بواسطة الوسيطة الثالثة بالفعل "تحت الغطاء".

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


 //   package.json /   const modulesRawPathsParts = await getModulesRawPaths( projectRoot, modulePath, moduleGroupName ); //         const modulesFilesPathsParts = entries(modulesRawPathsParts).reduce( (acc, [moduleName, moduleRawPath]) => { const rawFilename = moduleRawPath.pop(); const processedFilenames = processFileExtensions(rawFilename); const pathsWithFilenames = processedFilenames.map( filename => moduleRawPath.concat(filename) ); return { ...acc, [moduleName]: pathsWithFilenames }; }, {} ); //       const modulesFilesPaths = await Promise.all( entries(modulesFilesPathsParts).map(([moduleName, modulePathParts]) => Promise.all( modulePathParts.map(modulePathPart => buildPaths(projectRoot, modulePathPart)) ) .then(paths => paths.flat().filter(processedPath => processedPath)) .then(existingPaths => ({ [moduleName]: existingPaths })), ), ); const processedModulesFilesPaths = arrayToObject(modulesFilesPaths); //    ,       const availableModules = entries(processedModulesFilesPaths).reduce( (acc, [moduleName, modulePaths]) => (modulePaths.length === 0 ? acc : { ...acc, [moduleName]: modulePaths }), {}, ); //   return Promise.all( entries(availableModules).map(([moduleName, modulePaths]) => Promise.all(modulePaths.map(moduleLoadPath => //     : import(moduleLoadPath) )).then(loadedModule => ({ [moduleName]: loadedModule, })), ), ).then(arrayToObject); 

فقط اليسار ترك الكتابة على الغش


لماذا هذا كله؟


يبدو لي أن مسألة الواردات الديناميكية كانت غير مغطاة بشكل سيء للغاية وأن جميع هذه المكتبات في npm لم يتم تحديثها بشكل طفيف (أو كنت أبحث عنها بشكل سيئ؟) ، والتكنولوجيا تسمح لك بعمل جيد دون التسجيل والرسائل النصية القصيرة. آمل أن تهمك شفرة المصدر للمشروع وحالاتي لاستخدامها في مشاريعك ، مما يقلل بشكل طفيف من ازدواجية الكود عن طريق فك شفرة جديدة عكاز ، دراجة ، الإطار مما لا شك فيه مساعد مفيد.




الروابط ، البراهين ، الترجمات:



الكود المصدري لهذا الكود الخالي من العيوب هنا:
https://github.com/Melodyn/npm-dynamicimport/blob/master/lib/index.js#L93-L120
احصل على تجربة مستخدم لا تقدر بثمن هنا:
https://www.npmjs.com/package/@melodyn/dynamicimport
القطة هنا:
(^ ≗ω≗ ^)

Source: https://habr.com/ru/post/ar478974/


All Articles