@eggjs/utils
Advanced tools
+36
-1
@@ -0,1 +1,3 @@ | ||
| import { BundleModuleLoader, BundleModuleLoader as BundleModuleLoader$1 } from "@eggjs/typings"; | ||
| //#region src/import.d.ts | ||
@@ -13,4 +15,37 @@ interface ImportResolveOptions { | ||
| declare function importResolve(filepath: string, options?: ImportResolveOptions): string; | ||
| /** | ||
| * Module loader function type for V8 snapshot support. | ||
| * Called with the resolved absolute file path, returns the module exports. | ||
| */ | ||
| type SnapshotModuleLoader = (resolvedPath: string) => any; | ||
| /** | ||
| * Register a snapshot module loader that intercepts `importModule()` calls. | ||
| * | ||
| * When set, `importModule()` delegates to this loader instead of calling | ||
| * `import()` or `require()`. This is used by the V8 snapshot entry generator | ||
| * to provide pre-bundled modules — the bundler generates a static module map | ||
| * from the egg manifest and registers it via this API. | ||
| * | ||
| * Also sets `isESM = false` because the snapshot bundle is CJS and | ||
| * esbuild's `import.meta` polyfill causes incorrect ESM detection. | ||
| * | ||
| * Pass `undefined` to clear the loader and restore the auto-detected `isESM` | ||
| * value. Always clear it once snapshot mode is no longer needed (e.g. in test | ||
| * teardown) so the module-level state does not leak into other files when | ||
| * vitest runs with `isolate: false`. | ||
| */ | ||
| declare function setSnapshotModuleLoader(loader: SnapshotModuleLoader | undefined): void; | ||
| /** | ||
| * Register a bundle module loader. Uses globalThis so that bundled and | ||
| * external copies of @eggjs/utils share the same loader. | ||
| * | ||
| * The loader receives a POSIX-normalized filepath or virtual specifier before | ||
| * normal resolution runs. Return `undefined` to fall through to the default | ||
| * import path. Non-undefined hits use the same default unwrapping semantics as | ||
| * normal imports, including `importDefaultOnly` and double-default `__esModule` | ||
| * compatibility. | ||
| */ | ||
| declare function setBundleModuleLoader(loader: BundleModuleLoader | undefined): void; | ||
| declare function importModule(filepath: string, options?: ImportModuleOptions): Promise<any>; | ||
| //#endregion | ||
| export { ImportModuleOptions, ImportResolveOptions, getExtensions, getRequire, importModule, importResolve, isESM, isSupportTypeScript }; | ||
| export { type BundleModuleLoader$1 as BundleModuleLoader, ImportModuleOptions, ImportResolveOptions, SnapshotModuleLoader, getExtensions, getRequire, importModule, importResolve, isESM, isSupportTypeScript, setBundleModuleLoader, setSnapshotModuleLoader }; |
+79
-4
@@ -11,2 +11,14 @@ import { __require } from "./_virtual/rolldown_runtime.js"; | ||
| const debug = debuglog("egg/utils/import"); | ||
| let nativeDynamicImport; | ||
| /* v8 ignore next -- covered by the spawned Node fixture; Vitest cannot instrument this opaque import. */ | ||
| function getNativeDynamicImport() { | ||
| if (!nativeDynamicImport) try { | ||
| nativeDynamicImport = new Function("specifier", "return import(specifier);"); | ||
| } catch (err) { | ||
| const error = /* @__PURE__ */ new Error("Native dynamic import fallback for bundled module loader misses requires code generation from strings."); | ||
| error.cause = err; | ||
| throw error; | ||
| } | ||
| return nativeDynamicImport; | ||
| } | ||
| let isESM = true; | ||
@@ -18,2 +30,3 @@ try { | ||
| } | ||
| const detectedIsESM = isESM; | ||
| const nodeMajorVersion = parseInt(process.versions.node.split(".", 1)[0], 10); | ||
@@ -23,3 +36,3 @@ const supportImportMetaResolve = nodeMajorVersion >= 18; | ||
| function getRequire() { | ||
| if (!_customRequire) if (typeof __require !== "undefined") _customRequire = __require; | ||
| if (!_customRequire) if (typeof __require !== "undefined" && __require.extensions) _customRequire = __require; | ||
| else _customRequire = createRequire(process.cwd()); | ||
@@ -199,2 +212,7 @@ return _customRequire; | ||
| } | ||
| const bundleModuleLoader = globalThis.__EGG_BUNDLE_MODULE_LOADER__; | ||
| if (bundleModuleLoader && bundleModuleLoader(normalizeBundleModulePath(filepath)) !== void 0) { | ||
| debug("[importResolve:bundle] %o => %o", filepath, filepath); | ||
| return filepath; | ||
| } | ||
| const extname = path.extname(filepath); | ||
@@ -216,4 +234,59 @@ if (!isAbsolute && extname === ".json" || !isESM) moduleFilePath = getRequire().resolve(filepath, { paths }); | ||
| } | ||
| let _snapshotModuleLoader; | ||
| /** | ||
| * Register a snapshot module loader that intercepts `importModule()` calls. | ||
| * | ||
| * When set, `importModule()` delegates to this loader instead of calling | ||
| * `import()` or `require()`. This is used by the V8 snapshot entry generator | ||
| * to provide pre-bundled modules — the bundler generates a static module map | ||
| * from the egg manifest and registers it via this API. | ||
| * | ||
| * Also sets `isESM = false` because the snapshot bundle is CJS and | ||
| * esbuild's `import.meta` polyfill causes incorrect ESM detection. | ||
| * | ||
| * Pass `undefined` to clear the loader and restore the auto-detected `isESM` | ||
| * value. Always clear it once snapshot mode is no longer needed (e.g. in test | ||
| * teardown) so the module-level state does not leak into other files when | ||
| * vitest runs with `isolate: false`. | ||
| */ | ||
| function setSnapshotModuleLoader(loader) { | ||
| _snapshotModuleLoader = loader; | ||
| isESM = loader ? false : detectedIsESM; | ||
| } | ||
| function normalizeBundleModulePath(filepath) { | ||
| return filepath.split(path.win32.sep).join(path.posix.sep); | ||
| } | ||
| /** | ||
| * Register a bundle module loader. Uses globalThis so that bundled and | ||
| * external copies of @eggjs/utils share the same loader. | ||
| * | ||
| * The loader receives a POSIX-normalized filepath or virtual specifier before | ||
| * normal resolution runs. Return `undefined` to fall through to the default | ||
| * import path. Non-undefined hits use the same default unwrapping semantics as | ||
| * normal imports, including `importDefaultOnly` and double-default `__esModule` | ||
| * compatibility. | ||
| */ | ||
| function setBundleModuleLoader(loader) { | ||
| globalThis.__EGG_BUNDLE_MODULE_LOADER__ = loader; | ||
| } | ||
| async function importModule(filepath, options) { | ||
| const _bundleModuleLoader = globalThis.__EGG_BUNDLE_MODULE_LOADER__; | ||
| if (_bundleModuleLoader) { | ||
| const hit = _bundleModuleLoader(normalizeBundleModulePath(filepath)); | ||
| if (hit !== void 0) { | ||
| let obj$1 = hit; | ||
| if (obj$1?.default?.__esModule === true && "default" in obj$1.default) obj$1 = obj$1.default; | ||
| if (options?.importDefaultOnly && obj$1 && typeof obj$1 === "object" && "default" in obj$1) obj$1 = obj$1.default; | ||
| return obj$1; | ||
| } | ||
| } | ||
| const moduleFilePath = importResolve(filepath, options); | ||
| if (_snapshotModuleLoader) { | ||
| let obj$1 = _snapshotModuleLoader(moduleFilePath); | ||
| if (obj$1 && typeof obj$1 === "object" && obj$1.default?.__esModule === true && obj$1.default && "default" in obj$1.default) obj$1 = obj$1.default; | ||
| if (options?.importDefaultOnly) { | ||
| if (obj$1 && typeof obj$1 === "object" && "default" in obj$1) obj$1 = obj$1.default; | ||
| } | ||
| return obj$1; | ||
| } | ||
| let obj; | ||
@@ -223,5 +296,7 @@ if (isESM) { | ||
| debug("[importModule:start] await import fileUrl: %s, isESM: %s", fileUrl, isESM); | ||
| obj = await import(fileUrl); | ||
| /* v8 ignore if -- covered by the spawned Node fixture; Vitest cannot instrument this opaque import. */ | ||
| if (_bundleModuleLoader) obj = await getNativeDynamicImport()(fileUrl); | ||
| else obj = await import(fileUrl); | ||
| debug("[importModule:success] await import %o", fileUrl); | ||
| if (obj?.default?.__esModule === true && "default" in obj?.default) obj = obj.default; | ||
| if (obj?.default?.__esModule === true && obj.default && "default" in obj.default) obj = obj.default; | ||
| if (options?.importDefaultOnly) { | ||
@@ -240,2 +315,2 @@ if ("default" in obj) obj = obj.default; | ||
| //#endregion | ||
| export { getExtensions, getRequire, importModule, importResolve, isESM, isSupportTypeScript }; | ||
| export { getExtensions, getRequire, importModule, importResolve, isESM, isSupportTypeScript, setBundleModuleLoader, setSnapshotModuleLoader }; |
+2
-2
| import { getFrameworkOrEggPath } from "./deprecated.js"; | ||
| import { getFrameworkPath } from "./framework.js"; | ||
| import { findEggCore, getConfig, getLoadUnits, getLoader, getPlugins } from "./plugin.js"; | ||
| import { ImportModuleOptions, ImportResolveOptions, getExtensions, getRequire, importModule, importResolve, isESM, isSupportTypeScript } from "./import.js"; | ||
| import { BundleModuleLoader, ImportModuleOptions, ImportResolveOptions, SnapshotModuleLoader, getExtensions, getRequire, importModule, importResolve, isESM, isSupportTypeScript, setBundleModuleLoader, setSnapshotModuleLoader } from "./import.js"; | ||
| import { ImportResolveError } from "./error/ImportResolveError.js"; | ||
@@ -28,2 +28,2 @@ | ||
| //#endregion | ||
| export { EggType, ImportModuleOptions, ImportResolveError, ImportResolveOptions, _default as default, detectType, findEggCore, getConfig, getExtensions, getFrameworkOrEggPath, getFrameworkPath, getLoadUnits, getLoader, getPlugins, getRequire, importModule, importResolve, isESM, isSupportTypeScript }; | ||
| export { BundleModuleLoader, EggType, ImportModuleOptions, ImportResolveError, ImportResolveOptions, SnapshotModuleLoader, _default as default, detectType, findEggCore, getConfig, getExtensions, getFrameworkOrEggPath, getFrameworkPath, getLoadUnits, getLoader, getPlugins, getRequire, importModule, importResolve, isESM, isSupportTypeScript, setBundleModuleLoader, setSnapshotModuleLoader }; |
+2
-2
| import { getFrameworkOrEggPath } from "./deprecated.js"; | ||
| import { ImportResolveError } from "./error/ImportResolveError.js"; | ||
| import { getExtensions, getRequire, importModule, importResolve, isESM, isSupportTypeScript } from "./import.js"; | ||
| import { getExtensions, getRequire, importModule, importResolve, isESM, isSupportTypeScript, setBundleModuleLoader, setSnapshotModuleLoader } from "./import.js"; | ||
| import { getFrameworkPath } from "./framework.js"; | ||
@@ -45,2 +45,2 @@ import { findEggCore, getConfig, getLoadUnits, getLoader, getPlugins } from "./plugin.js"; | ||
| //#endregion | ||
| export { EggType, ImportResolveError, src_default as default, detectType, findEggCore, getConfig, getExtensions, getFrameworkOrEggPath, getFrameworkPath, getLoadUnits, getLoader, getPlugins, getRequire, importModule, importResolve, isESM, isSupportTypeScript }; | ||
| export { EggType, ImportResolveError, src_default as default, detectType, findEggCore, getConfig, getExtensions, getFrameworkOrEggPath, getFrameworkPath, getLoadUnits, getLoader, getPlugins, getRequire, importModule, importResolve, isESM, isSupportTypeScript, setBundleModuleLoader, setSnapshotModuleLoader }; |
+4
-2
| { | ||
| "name": "@eggjs/utils", | ||
| "version": "5.0.2-beta.9", | ||
| "version": "5.0.2-beta.10", | ||
| "description": "Utils for all egg projects", | ||
@@ -31,3 +31,5 @@ "keywords": [ | ||
| }, | ||
| "dependencies": {}, | ||
| "dependencies": { | ||
| "@eggjs/typings": "4.1.2-beta.10" | ||
| }, | ||
| "devDependencies": { | ||
@@ -34,0 +36,0 @@ "coffee": "5", |
+16
-0
@@ -45,2 +45,18 @@ # @eggjs/utils | ||
| ### `setBundleModuleLoader(loader)` | ||
| Register a module loader hook for bundled Egg apps. The hook runs before the | ||
| normal `importModule()` resolution path. | ||
| - {Function | undefined} loader - a synchronous function that receives the | ||
| original `filepath` argument passed to `importModule()` after POSIX separator | ||
| normalization, or a virtual specifier. It does not receive the resolved | ||
| absolute file path from `importResolve()`. Return `undefined` to fall back to | ||
| the normal import path. | ||
| The bundle loader is stored on `globalThis`, so bundled and external copies of | ||
| `@eggjs/utils` share the same loader. Non-`undefined` results follow the same | ||
| default export unwrapping rules as `importModule()`, including | ||
| `importDefaultOnly`. | ||
| ## License | ||
@@ -47,0 +63,0 @@ |
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
34456
22.69%733
17.47%70
29.63%1
Infinity%1
Infinity%+ Added
+ Added