@gez/import
Advanced tools
Comparing version 3.0.0-beta.22 to 3.0.0-beta.23
@@ -18,3 +18,3 @@ { | ||
"@biomejs/biome": "1.9.4", | ||
"@gez/lint": "3.0.0-beta.22", | ||
"@gez/lint": "3.0.0-beta.23", | ||
"@types/node": "22.9.0", | ||
@@ -27,3 +27,3 @@ "@vitest/coverage-v8": "2.1.5", | ||
}, | ||
"version": "3.0.0-beta.22", | ||
"version": "3.0.0-beta.23", | ||
"type": "module", | ||
@@ -46,3 +46,3 @@ "private": false, | ||
], | ||
"gitHead": "a4bced74182cb438dccc53200451c1ded5954635" | ||
"gitHead": "7cf67e43fc586634e4709d67d5dd402c8eb9c884" | ||
} |
@@ -8,2 +8,24 @@ import fs from 'node:fs'; | ||
async function importBuiltinModule(specifier: string, context: vm.Context) { | ||
const nodeModule = await import(specifier); | ||
const keys = Object.keys(nodeModule); | ||
const module = new vm.SyntheticModule( | ||
keys, | ||
function evaluateCallback() { | ||
keys.forEach((key) => { | ||
this.setExport(key, nodeModule[key]); | ||
}); | ||
}, | ||
{ | ||
identifier: specifier, | ||
context: context | ||
} | ||
); | ||
await module.link(() => { | ||
throw new TypeError(`Native modules should not be linked`); | ||
}); | ||
await module.evaluate(); | ||
return module; | ||
} | ||
/** | ||
@@ -14,2 +36,18 @@ * 创建一个使用 vm 实现的 importmap 的 import 函数,可以创建多次来实现热更新效果,适合开发使用。 | ||
const parsedImportMap = IM.parse(importMap, baseURL); | ||
const parse = (specifier: string, parent: string) => { | ||
const result = IM.resolve(specifier, parsedImportMap, new URL(parent)); | ||
let filename: string; | ||
if (result.matched && result.resolvedImport) { | ||
filename = result.resolvedImport.href; | ||
} else { | ||
filename = import.meta.resolve(specifier, parent); | ||
} | ||
const url = new URL(filename); | ||
return { | ||
filename, | ||
url, | ||
pathname: url.pathname | ||
}; | ||
}; | ||
async function moduleLinker( | ||
@@ -19,53 +57,43 @@ specifier: string, | ||
context: vm.Context, | ||
cache = new Map<string, Promise<vm.SourceTextModule>>() | ||
cache: Map<string, Promise<vm.SourceTextModule>>, | ||
moduleIds: string[] | ||
) { | ||
if (isBuiltin(specifier)) { | ||
const nodeModule = await import(specifier); | ||
const keys = Object.keys(nodeModule); | ||
const module = new vm.SyntheticModule( | ||
keys, | ||
function evaluateCallback() { | ||
keys.forEach((key) => { | ||
this.setExport(key, nodeModule[key]); | ||
}); | ||
}, | ||
{ | ||
identifier: specifier, | ||
context: context | ||
} | ||
return importBuiltinModule(specifier, context); | ||
} | ||
const parsed = parse(specifier, parent); | ||
if (moduleIds.includes(parsed.pathname)) { | ||
throw new RangeError( | ||
`Module circular reference: \n ${JSON.stringify([...moduleIds, parsed.pathname], null, 4)}` | ||
); | ||
await module.link(() => { | ||
throw new TypeError(`Native modules should not be linked`); | ||
}); | ||
await module.evaluate(); | ||
return module; | ||
} | ||
const result = IM.resolve(specifier, parsedImportMap, new URL(parent)); | ||
let filename: string; | ||
if (result.matched && result.resolvedImport) { | ||
filename = result.resolvedImport.href; | ||
} else { | ||
filename = import.meta.resolve(specifier, parent); | ||
} | ||
const url = new URL(filename); | ||
const readFilename = url.pathname; | ||
let module = cache.get(readFilename); | ||
const module = cache.get(parsed.pathname); | ||
if (module) { | ||
return module; | ||
} | ||
const dirname = path.dirname(filename); | ||
const build = async (): Promise<vm.SourceTextModule> => { | ||
const text = fs.readFileSync(readFilename, 'utf-8'); | ||
const pe = new Promise<vm.SourceTextModule>((resolve) => { | ||
process.nextTick(() => { | ||
moduleBuild().then(resolve); | ||
}); | ||
}); | ||
const dirname = path.dirname(parsed.filename); | ||
cache.set(parsed.pathname, pe); | ||
return pe; | ||
async function moduleBuild(): Promise<vm.SourceTextModule> { | ||
const text = fs.readFileSync(parsed.pathname, 'utf-8'); | ||
const module = new vm.SourceTextModule(text, { | ||
initializeImportMeta: (meta) => { | ||
meta.filename = filename; | ||
meta.filename = parsed.filename; | ||
meta.dirname = dirname; | ||
meta.resolve = ( | ||
specifier: string, | ||
parent: string | URL = url | ||
parent: string | URL = parsed.url | ||
) => { | ||
return import.meta.resolve(specifier, parent); | ||
}; | ||
meta.url = url.toString(); | ||
meta.url = parsed.url.toString(); | ||
}, | ||
@@ -78,6 +106,7 @@ identifier: specifier, | ||
specifier, | ||
filename, | ||
parsed.filename, | ||
// @ts-ignore | ||
referrer.context, | ||
cache | ||
cache, | ||
[...moduleIds, parsed.pathname] | ||
); | ||
@@ -89,5 +118,6 @@ } | ||
specifier, | ||
filename, | ||
parsed.filename, | ||
referrer.context, | ||
cache | ||
cache, | ||
[...moduleIds, parsed.pathname] | ||
); | ||
@@ -97,6 +127,3 @@ }); | ||
return module; | ||
}; | ||
module = build(); | ||
cache.set(readFilename, module); | ||
return module; | ||
} | ||
} | ||
@@ -110,3 +137,9 @@ return async ( | ||
const context = vm.createContext(sandbox, options); | ||
const module = await moduleLinker(specifier, parent, context); | ||
const module = await moduleLinker( | ||
specifier, | ||
parent, | ||
context, | ||
new Map(), | ||
[] | ||
); | ||
@@ -113,0 +146,0 @@ return module.namespace as Record<string, any>; |
Sorry, the diff of this file is not supported yet
14966
373