使用动态导入自动加载模块

最近 Node.js中宣布了对ECMAScript模块的支持,而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,从而可以导入...


我想写一些像顶级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中创建一个autoload部分,并创建一个工具,该工具通过键读取模块名称,并从该值读取文件路径:


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

在使用typecipt的情况下,有一个令人烦恼的时刻,即在构建应用程序后扩展会发生变化,并且存在不止两个扩展名: 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加载模块,在这种情况下,模块名称(自动加载部分中的键)由已经“在幕后”的第三个参数传递。

构建路径是一项微不足道的任务,我们只需遍历数组并选择星星的所有子目录,当数组结束时,将其返回并将模块加载到数组中。 结果,在几个晚上,我以这种方式为自己草拟了该解决方案:


 //   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中的所有此类库都没有稍作更新(或者我看上去很糟糕吗?),该技术使您无需注册和发送SMS就能表现出色。 我希望该项目的源代码及其使用案例能使您感兴趣,以便在您的项目中使用,通过拧入新代码来略微减少代码重复 拐杖自行车框架 无疑是有用的帮手。




链接,证明,翻译:



此完美代码的源代码在这里:
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/zh-CN478974/


All Articles