尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

MikroORM CLI 的 TypeScript Loader 机制:自动探测、手动配置与实体元数据加载全解析

MikroORM CLI 的 TypeScript Loader 机制:自动探测、手动配置与实体元数据加载全解析 后端【免费下载链接】mikro-ormTypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, MariaDB, MS SQL Server, PostgreSQL and SQLite/libSQL databases.项目地址https://gitcode.com/gh_mirrors/mi/mikro-orm点击查看免费下载MikroORM 的 CLI 工具需要能够import()你的 TypeScript 文件——既包括 ORM 配置文件本身也包括通过配置发现的实体文件。Node.js 如今虽然可以原生运行 TypeScript但默认只会剥离类型遇到使用枚举enum或装饰器decorator的文件依然会解析失败而用装饰器定义实体恰恰是 MikroORM 最常见的用法。因此 CLI 会在加载配置之前注册一个受支持的 TypeScript Loader加载器。本文以仓库内 typescript-loaders.md 文档为主线结合 CLIHelper.ts 源码完整讲解 Loader 的自动探测逻辑、preferTs/tsLoader/tsConfigPath三类配置入口、全部六个受支持 Loader 的差异与选择方式以及 Nub 的特殊行为与预编译场景的替代方案帮助你彻底理解 CLI 如何读懂你的 TypeScript 实体。为什么 CLI 需要 TypeScript LoaderMikroORM 的核心职责之一是从实体类中提取元数据。无论是Entity()、Property()这些装饰器还是enum、interface这类仅存在于编译期的语法都要求 CLI 在运行时真正执行 TypeScript 源码而不只是读取文本。CLI 的整个启动流程从configure()开始见 CLIConfigurator.tsif (settings.preferTs ! false) { const preferTs await CLIHelper.registerTypeScriptSupport(settings.tsConfigPath, settings.tsLoader); if (!preferTs) { process.env.MIKRO_ORM_CLI_PREFER_TS ?? 0; } }这段代码揭示了几条关键事实只要preferTs没有被显式设为falseCLI 启动时就会尝试注册 TypeScript Loader注册动作由CLIHelper.registerTypeScriptSupport()完成它接收tsConfigPath与tsLoader两个参数如果注册失败CLI 会把MIKRO_ORM_CLI_PREFER_TS环境变量置为0即降级为不偏好 TS模式随后回退到编译后的 JavaScript 配置而忽略 TypeScript 配置。也就是说Loader 的核心价值在于让 CLI 能够解析那些 Node.js 原生运行时无法处理的语法装饰器、枚举等从而顺利加载mikro-orm.config.ts及其发现的实体文件。自动探测DetectionCLI 如何判断要不要用 TypeScriptTypeScript 支持是自动检测的检测依据包括配置文件的扩展名、process.execArgv中是否出现 TS Loader、当前使用的测试运行器等。对应实现位于 Utils.ts 的Utils.detectTypeScriptSupport()static detectTypeScriptSupport(): boolean { return ( process.argv?.[0]?.endsWith(ts-node) || // 直接通过 ts-node 运行 !!process.env?.MIKRO_ORM_CLI_ALWAYS_ALLOW_TS || // 被 registerTypeScriptSupport() 显式开启 !!process.env?.TS_JEST || // 检测到 ts-jest !!process.env?.VITEST || // 检测到 vitest !!process.versions?.bun || // 检测到 bun process.argv?.slice(1).some(arg /\.([mc]?ts|tsx)$/.exec(arg)) || // 正在执行 .ts 文件 process.execArgv?.some(arg { return ( arg.includes(ts-node) || arg.includes(swc-node/register) || arg.includes(node_modules/tsx/) || arg.includes(oxc-node/core) || arg.includes(nubjs/loader) ); }) ); }从源码可以梳理出完整的探测信号清单探测信号说明process.argv[0]以ts-node结尾进程由 ts-node 直接启动MIKRO_ORM_CLI_ALWAYS_ALLOW_TS环境变量被registerTypeScriptSupport()设置强制允许 TSTS_JEST环境变量检测到 ts-jest 测试环境VITEST环境变量检测到 vitest 测试环境process.versions.bun运行在 Bun 运行时下启动参数中包含.ts/.mts/.cts/.tsx文件正在直接执行 TypeScript 文件process.execArgv中出现上述任一 Loader进程已通过--import等方式注册了 TS Loader此外在 CLIHelper.ts 的getSettings()中还有一条补充规则如果通过MIKRO_ORM_CLI_CONFIG环境变量显式指定的配置文件以.ts结尾preferTs会被强制置为true。该探测结果还直接影响getConfigPaths()见 CLIHelper.ts生成候选配置文件路径的顺序当探测到 TS 支持时会优先查找./src/mikro-orm.config.ts与./mikro-orm.config.ts再依次尝试./{dist|build|src}/mikro-orm.config.js与./mikro-orm.config.js反之所有.ts候选会被过滤掉直接回退到编译产物。通过 preferTs 强制开启如果自动探测的结果不符合预期可以通过package.json中的mikro-orm配置节强制开启mikro-orm: { preferTs: true }也可以使用MIKRO_ORM_CLI_PREFER_TS环境变量覆盖。从 CLIHelper.ts 的实现看环境变量优先于package.json配置且布尔解析规则为[true, t, 1]视为真值大小写不敏感。同样的机制也会在getORM()中生效见 CLIHelper.ts只要settings.preferTs ! falseORM 配置就会被显式置为preferTs: true从而让实体发现discovery优先使用entitiesTs指向的 TypeScript 源文件。受支持的 Loader 一览registerTypeScriptSupport()内部维护了一张 Loader 表见 CLIHelper.tsconst loaders { oxc: { esm: oxc-node/core/register, cjs: oxc-node/core/register }, swc: { esm: swc-node/register/esm-register, cjs: swc-node/register }, tsx: { esm: tsx/esm/api, cjs: tsx/cjs/api, cb: (tsx: any) tsx.register({ tsconfig: configPath }) }, jiti: { cjs: jiti/register, cb: setEsmImportProvider }, tsimp: { cjs: tsimp/import, cb: setEsmImportProvider }, nub: { esm: nubjs/loader, cjs: nubjs/loader }, } as const;结合文档与源码六个受支持的 Loader 及其特性如下Loader依赖包是否支持元数据反射说明oxcoxc-node/core✅基于 Rust 编写的 oxc 编译器速度快通过oxc-node/core/register注册swcswc-node/registerswc/core✅基于 SWC 的注册器ESM 下走esm-register入口tsxtsx❌流行的一体化运行工具通过tsx.register({ tsconfig: configPath })注册并显式传入 tsconfig 路径jitijiti❌轻量级运行时通过jiti/register注册并额外安装 ESM 动态导入提供器tsimptsimp❌TypeScript 官方维护的导入器通过tsimp/import注册nubnubjs/loader✅自 v7.2 起可用通过nubjs/loader注册行为特殊见下文注意每个 Loader 条目都同时声明了esm与cjs两个入口。注册逻辑见 CLIHelper.ts会根据项目是否为 ESM 选择对应入口CLIHelper.isESM()通过package.json的type: module字段判断。此外注册前还会预设几个环境变量见 CLIHelper.tsSWC_NODE_PROJECT、TSIMP_PROJECT指向 tsconfig 路径MIKRO_ORM_CLI_ALWAYS_ALLOW_TS被置为1。关于元数据反射的含义文档中强调的 metadata reflection指的是 Loader 是否尊重emitDecoratorMetadata编译选项——这是ReflectMetadataProvider配合传统legacy装饰器工作时的硬性前提因为该 Provider 需要从装饰器元数据中读取属性类型。详见 metadata-providers.md 中关于ReflectMetadataProvider的说明在 MikroORM v7 中ReflectMetadataProvider随 legacy 装饰器定义一起位于mikro-orm/decorators/legacy包中只支持 legacy 装饰器与emitDecoratorMetadata选项——ES 标准装饰器不支持元数据反射。因此如果你的实体同时使用legacy 装饰器 ReflectMetadataProvider就必须选择 oxc、swc 或 nub 这类支持元数据反射的 Loader如果你使用TsMorphMetadataProvider、ReflectMetadataProvider之外的其他 Provider或根本不依赖反射则不受此限制若要启用反射还需在tsconfig.json中打开emitDecoratorMetadata与experimentalDecorators两个选项。选择 Loaderauto 与显式指定默认值为auto此时 CLI 会按照oxc → swc → tsx → jiti → tsimp → nub的顺序逐个尝试选中依赖中第一个可用者即Utils.tryImport()能成功导入的那个。这一顺序也直接对应源码中loaders对象的键顺序以及 CLIHelper.ts 注释里描述的注册顺序。要显式指定在package.json中设置tsLoadermikro-orm: { tsLoader: jiti }或者通过MIKRO_ORM_CLI_TS_LOADER环境变量覆盖。从 CLIHelper.ts 可见环境变量的优先级更高。显式指定的关键行为差异没有回退。源码中explicitLoader ! auto时的处理逻辑见 CLIHelper.ts清晰地展示了这一点for (const loader of Utils.keys(loaders)) { if (loader nub !usesDefaultTsConfig) { continue; } if (explicitLoader ! auto loader ! explicitLoader) { continue; } // ... try { mod await Utils.tryImport({ module }); } catch (e) { const error new Error(Failed to load TypeScript loader \${loader}\ (${module}): ${e.message}, { cause: e }); if (explicitLoader ! auto) { throw error; // 显式指定时立即抛出 } errors.push(error); continue; // auto 模式下继续尝试下一个 } }也就是说如果显式指定的 Loader 未安装或加载失败CLI 会直接抛出异常而不会尝试下一个候选。与之相对auto 模式下某个 Loader 加载失败只会被记录随后继续尝试下一个。还有一个值得注意的边界行为auto 模式下如果某个 Loader 已安装但加载失败brokenCLI 会将其视为真实问题而非缺失依赖直接抛出汇总所有错误信息的异常见 CLIHelper.ts。只有当所有 Loader 都未安装时才会打印警告并返回false最终回退到编译后的 JS 配置。警告信息还给出了安装提示Neitheroxc,swc,tsx,jiti,tsimpnornubfound in the project dependencies, support for working with TypeScript files might not work. To useoxc, installoxc-node/core. To useswc, install bothswc-node/registerandswc/core.仓库中的单元测试完整覆盖了上述行为见 CLIHelper.test.ts例如分别验证了六个 Loader 各自对应的注册模块路径、Nub 作为最终自动回退MIKRO_ORM_CLI_TS_LOADER被置为nub、已存在的 Loader 优先于 Nub 回退、以及配置自定义 tsconfig 路径时跳过 Nub 等场景。tsconfig.json哪些 Loader 会用到它部分 Loader 会直接指向你的tsconfig.json默认使用当前工作目录下的tsconfig.json。可以通过package.json的tsConfigPath设置或MIKRO_ORM_CLI_TS_CONFIG_PATH环境变量指定其他路径mikro-orm: { tsConfigPath: ./tsconfig.cli.json }对应到源码注册前SWC_NODE_PROJECT与TSIMP_PROJECT都会被设为该路径见 CLIHelper.ts而 tsx 则通过tsx.register({ tsconfig: configPath })回调显式传入见 CLIHelper.ts。也就是说swc、tsimp、tsx 三个 Loader 都会使用自定义 tsconfig 路径oxc 与 jiti 不使用nub 则完全自行解析见下文。测试用例也验证了自定义 tsconfig 路径下 SWC 的行为swc-node/register/esm-register会合并扩展的 tsconfig见 CLIHelper.test.ts。Nub特殊的 LoaderNub 是 v7.2 新增的 Loader经由nubjs/loader注册行为与其他 Loader 有明显差异使用前务必注意1. 自行解析 tsconfig无法指定自定义路径。Nub 总是相对于每个被导入文件解析最近的tsconfig.json无法被指向自定义路径。因此在package.json中同时配置tsLoader: nub与tsConfigPath会直接抛出异常自动选择auto模式下只要配置了自定义 tsconfig 路径Nub 就会被跳过。对应实现见 CLIHelper.ts 与 CLIHelper.tsconst usesDefaultTsConfig fs.absolutePath(configPath) fs.absolutePath(tsconfig.json); if (explicitLoader nub !usesDefaultTsConfig) { throw new Error( The nub loader does not support a custom tsconfig path. Use the project tsconfig.json or select another loader., ); } // ... for (const loader of Utils.keys(loaders)) { if (loader nub !usesDefaultTsConfig) { continue; // auto 模式下跳过 } // ... }同时auto 模式下因自定义 tsconfig 路径而跳过 Nub 时警告信息会追加一句提示Thenubloader was skipped as a custom tsconfig path is configured.见 CLIHelper.ts。2. 仅支持 legacy 装饰器。Nub 只理解传统装饰器语法因此要求tsconfig.json中设置experimentalDecorators: true它会拒绝使用 ES 标准装饰器见 using-decorators.md的文件。如果你的实体使用了 ES 装饰器请改用其他 Loader。若你的项目满足条件使用默认 tsconfig、采用 legacy 装饰器可以显式选择 Nubmikro-orm: { tsLoader: nub }测试覆盖显示auto 模式下当只有nubjs/loader可用时它会被选为最终回退并写入MIKRO_ORM_CLI_TS_LOADER环境变量见 CLIHelper.test.ts而当 oxc 可用时会优先选择 oxc 而不会尝试 Nub见 CLIHelper.test.ts。预先编译Compiling ahead of time替代方案上述 Loader 全部服务于直接运行 TypeScript这一场景。如果你的项目改用tsc、Babel 或 SWC 预先编译就不需要它们但要注意各自对装饰器的特殊要求详见 usage-with-transpilers.mdBabel需要安装babel-plugin-transform-typescript-metadata、babel/plugin-proposal-decoratorslegacy: true与babel/plugin-proposal-class-propertiesloose: true三个插件并设置BABEL_DECORATORS_COMPATtrue环境变量SWC默认不发射装饰器元数据无论 tsconfig 如何配置且目标为es5时会混淆类名影响从类名推断表名的场景。需要在.swcrc中开启jsc.parser.decorators、jsc.transform.decoratorMetadata、jsc.transform.legacyDecorator并将jsc.target设为es2016以上推荐esnext若启用压缩还需设置jsc.keepClassNames: true。这种编译后运行的方式与 Loader 方案并不冲突Loader 解决的是开发期直接跑 TS 的问题编译产物则用于生产部署。选择哪种取决于你的构建流水线与实体元数据的提供方式。小结MikroORM CLI 的 TypeScript Loader 机制可以概括为三层探测层通过Utils.detectTypeScriptSupport()综合配置文件扩展名、execArgv、测试运行器、运行时Bun等信号自动判断是否需要 TS 支持并可通过preferTs或MIKRO_ORM_CLI_PREFER_TS强制控制注册层registerTypeScriptSupport()按 oxc → swc → tsx → jiti → tsimp → nub 的顺序尝试加载支持tsLoader/MIKRO_ORM_CLI_TS_LOADER显式指定无回退并用tsConfigPath/MIKRO_ORM_CLI_TS_CONFIG_PATH控制 tsconfig 指向回退层全部 Loader 均不可用时打印警告并回退到编译后的 JS 配置或提前用tsc/Babel/SWC 编译项目参见 usage-with-transpilers.md。关键决策点在于你的元数据提供方式如果依赖ReflectMetadataProvider legacy 装饰器必须选择 oxc、swc 或 nub如果实体使用 ES 标准装饰器则应避开 Nub并参考 using-decorators.md 选择合适的组合。赞分享后端【免费下载链接】mikro-ormTypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, MariaDB, MS SQL Server, PostgreSQL and SQLite/libSQL databases.项目地址https://gitcode.com/gh_mirrors/mi/mikro-orm点击查看免费下载相关推荐NocoBase 数据加载方式配置指南自动加载与手动加载auto/manual的原理与实战NocoBase 数据加载方式配置指南自动加载与手动加载auto/manual的原理与实战 在 NocoBase 的界面搭建Interface Buil低代码后端前端人工智能AI 应用工作流自动化深入掌握 MikroORM 实体定义装饰器、EntitySchema 与元数据机制全解析深入掌握 MikroORM 实体定义装饰器、EntitySchema 与元数据机制全解析 在 MikroORM 中实体Entity是数据模型的核心载体—后端Ultralytics KITTI 检测数据集配置解析、自动下载机制与 YOLO26 训练实战Ultralytics KITTI 检测数据集配置解析、自动下载机制与 YOLO26 训练实战 本文围绕 Ultralytics 仓库中为 KITTI 数据集人工智能深度学习计算机视觉预训练创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表