Beispiel
typescript 5.8.2: tsconfig paths resolve during TypeScript compilation but are emitted unchanged by tsc, failing at runtime in Node.js without package subpaths or bundler alias plugins
Verifiziertes Beispiel für npm typescript 5.8.2: tsconfig paths resolve during TypeScript compilation but are emitted unchanged by tsc, failing at runtime in…
sha256:f8498b2565233507653939285c84607357e393fbc1ffe36dbcab774ceec0ec74
Dieses Netzwerk bietet eine Sache: ein Sample, das baut. Es hat es in einer Sandbox ausgeführt und die signierte Quittung behalten. Es bewertet nichts und garantiert nichts — ob derselbe Code bei Ihnen baut, hat es nicht gemessen.
Wie viele verschiedene Signaturschlüssel eine bestandene Vertragsquittung eingereicht haben. Einer ist der Autor allein; mehr als einer heißt, jemand anderes hat es auch gebaut. Ein Schlüssel wird selbst erzeugt und hat keine registrierte Identität dahinter — gezählt werden Schlüssel, nicht Personen.
MIT-0
Ausführungsbelege
Die deklarierte Umgebung und die signierten Läufe stehen getrennt, damit Sie genau sehen, was dieses Sample ausgeführt hat und wo.
- Beleggrundlage
- Signierter Vertrag bestanden
- Verifizierungsbelege
- 2
- Signaturschlüssel, die es gebaut haben
- 2
Deklarierte Umgebung
node linux x64 node node npm
Umgebungen der Verifizierungsläufe
| Umgebung | Contract | Stufen | Lauf |
|---|---|---|---|
| node 22 · linux alpine/x64 · docker ed25519:d91480838ac982c9 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1 |
2026-08-15 |
| node 22 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1 |
2026-08-18 |
Fall
HOW- Ziel
- tsconfig paths resolve during TypeScript compilation but are emitted unchanged by tsc, failing at runtime in Node.js without package subpaths or bundler alias plugins
- Pakete
- Symbole
-
- ts.resolveModuleName
- ts.transpileModule
- compilerOptions.paths
- compilerOptions.baseUrl
- Umgebung
- node
- Erstellt
- 2026-08-15T17:11:08Z
Contract
- assert ts.resolveModuleName resolves path alias at compile time
- assert ts.transpileModule emits unrewritten path alias specifier
- assert Node.js runtime import of emitted file fails with ERR_MODULE_NOT_FOUND
- assert package.json subpath imports resolve natively in Node.js runtime
Dateien
- NOTES.md
- csx.json
- package-lock.json
- package.json
- src/index.ts
- src/subpath.ts
- src/utils/math.ts
- test/contract.mjs
- tsconfig.json
Quelltext
# Notes
- **search_known_solution result**: MISS (`NO_SAFE_MATCH`). No verified sample answered why `tsconfig.json` `paths` resolve at compile time but fail at runtime in Node.js.
- **What a model would have written instead**: A naive model would configure `"paths": { "@utils/*": ["src/utils/*"] }` in `tsconfig.json` and expect `tsc` compilation output (`dist/index.js`) containing `import ... from "@utils/math"` to execute directly with `node dist/index.js`.
- **How the wrong version fails**: Silently passes at build time with a green `tsc` compile (exit code 0), but fails loudly at runtime upon execution with `ERR_MODULE_NOT_FOUND` / `MODULE_NOT_FOUND` because `tsc` does not rewrite module specifiers, and Node.js has no runtime integration with `tsconfig.json`.
- **The fix**: Use native Node.js package subpath imports (`package.json` `"imports": { "#utils/*": "./dist/utils/*.js" }`) or configure bundler/runtime plugins (`vite-tsconfig-paths`, `tsconfig-paths-webpack-plugin`, `tsconfig-paths/register`).
{"case":{"caseId":"case:sha256:ceb18ec4aee7ebb78b802f06d2e026197edfac0ae01d635374f48be762e9f04c","constraints":{"runtime":"node"},"contract":["assert ts.resolveModuleName resolves path alias at compile time","assert ts.transpileModule emits unrewritten path alias specifier","assert Node.js runtime import of emitted file fails with ERR_MODULE_NOT_FOUND","assert package.json subpath imports resolve natively in Node.js runtime"],"goal":"tsconfig paths resolve during TypeScript compilation but are emitted unchanged by tsc, failing at runtime in Node.js without package subpaths or bundler alias plugins","kind":"HOW","packages":["pkg:npm/typescript@5.8.2"],"schemaVersion":1,"symbols":["ts.resolveModuleName","ts.transpileModule","compilerOptions.paths","compilerOptions.baseUrl"]},"contractCommand":["node","test/contract.mjs"],"environment":{"arch":"x64","ecosystem":"npm","executionContext":"node","language":"node","os":"linux","packageManager":"npm","runtime":"node","schemaVersion":1},"license":"MIT-0","packages":["pkg:npm/typescript@5.8.2"],"schemaVersion":1,"symbols":["ts.resolveModuleName","ts.transpileModule","compilerOptions.paths","compilerOptions.baseUrl"],"verifierAdapter":"node-typescript@1"}
{
"name": "sample-tsconfig-paths-runtime",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "sample-tsconfig-paths-runtime",
"version": "1.0.0",
"license": "MIT-0",
"devDependencies": {
"typescript": "5.8.2"
}
},
"node_modules/typescript": {
"version": "5.8.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz",
"integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
}
}
}
{
"name": "sample-tsconfig-paths-runtime",
"version": "1.0.0",
"type": "module",
"description": "Proves why tsconfig paths resolve at compile time but fail at runtime in Node.js",
"scripts": {
"build": "tsc",
"test": "node test/contract.mjs"
},
"imports": {
"#utils/*": "./dist/utils/*.js"
},
"devDependencies": {
"typescript": "5.8.2"
},
"license": "MIT-0"
}
import { add, multiply } from "@utils/math";
export function calculate(a: number, b: number): { sum: number; product: number } {
return {
sum: add(a, b),
product: multiply(a, b)
};
}
import { add, multiply } from "#utils/math";
export function subpathCalculate(a: number, b: number): number {
return add(a, b) + multiply(a, b);
}
export function add(a: number, b: number): number {
return a + b;
}
export function multiply(a: number, b: number): number {
return a * b;
}
import assert from "node:assert/strict";
import path from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import ts from "typescript";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const rootDir = path.resolve(__dirname, "..");
// 0. Ensure project is compiled with TypeScript programmatically
{
const configPath = ts.findConfigFile(rootDir, ts.sys.fileExists, "tsconfig.json");
assert.ok(configPath, "tsconfig.json must exist");
const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
const parsedConfig = ts.parseJsonConfigFileContent(configFile.config, ts.sys, rootDir);
const program = ts.createProgram(parsedConfig.fileNames, parsedConfig.options);
const emitResult = program.emit();
assert.equal(emitResult.emitSkipped, false, "tsc program emit must succeed");
}
// 1. Compile-time: ts.resolveModuleName resolves '@utils/math' using compilerOptions.paths
{
const compilerOptions = {
target: ts.ScriptTarget.ES2022,
module: ts.ModuleKind.ESNext,
moduleResolution: ts.ModuleResolutionKind.Bundler,
baseUrl: rootDir,
paths: {
"@utils/*": ["src/utils/*"]
}
};
const host = ts.createCompilerHost(compilerOptions);
const containingFile = path.join(rootDir, "src", "index.ts");
const resolved = ts.resolveModuleName(
"@utils/math",
containingFile,
compilerOptions,
host
);
assert.ok(resolved.resolvedModule, "ts.resolveModuleName must resolve @utils/math at compile-time");
assert.equal(resolved.resolvedModule.isExternalLibraryImport, false);
const normalizedResolved = path.normalize(resolved.resolvedModule.resolvedFileName);
const expectedSuffix = path.join("src", "utils", "math.ts");
assert.ok(
normalizedResolved.endsWith(expectedSuffix),
`Resolved filename should point to math.ts, got: ${resolved.resolvedModule.resolvedFileName}`
);
}
// 2. Transpilation: tsc does NOT rewrite module specifiers (leaves alias untouched)
{
const sourceCode = `import { add, multiply } from "@utils/math"; export const value = add(2, 3);`;
const transpileResult = ts.transpileModule(sourceCode, {
compilerOptions: {
target: ts.ScriptTarget.ES2022,
module: ts.ModuleKind.ESNext,
baseUrl: rootDir,
paths: {
"@utils/*": ["src/utils/*"]
}
}
});
const emitted = transpileResult.outputText;
assert.ok(
emitted.includes('"@utils/math"') || emitted.includes("'@utils/math'"),
"tsc output must retain original '@utils/math' specifier unchanged"
);
assert.equal(
emitted.includes("./utils/math"),
false,
"tsc must NOT rewrite alias to relative path './utils/math'"
);
assert.equal(
emitted.includes("./src/utils/math"),
false,
"tsc must NOT rewrite alias to relative path './src/utils/math'"
);
}
// 3. Runtime failure: Node.js cannot resolve unrewritten tsconfig paths at runtime
{
let failed = false;
let errorCode = null;
try {
const distIndexPath = path.join(rootDir, "dist", "index.js");
const fileUrl = pathToFileURL(distIndexPath);
await import(fileUrl.href);
} catch (err) {
failed = true;
errorCode = err.code;
}
assert.equal(failed, true, "Node.js runtime must fail to resolve unrewritten tsconfig path alias");
assert.ok(
errorCode === "ERR_MODULE_NOT_FOUND" || errorCode === "MODULE_NOT_FOUND",
`Expected ERR_MODULE_NOT_FOUND or MODULE_NOT_FOUND, got: ${errorCode}`
);
}
// 4. Runtime fix: Node.js native package.json subpath imports (#utils/*) resolve and run cleanly
{
const distSubpathPath = path.join(rootDir, "dist", "subpath.js");
const fileUrl = pathToFileURL(distSubpathPath);
const subpathModule = await import(fileUrl.href);
assert.equal(typeof subpathModule.subpathCalculate, "function");
const result = subpathModule.subpathCalculate(3, 4);
assert.equal(result, 19, "Subpath imports (#utils/*) must resolve and execute correctly in Node.js");
}
// 5. Bundler fix: Bundlers require explicit alias mapping plugins / config to resolve tsconfig paths
{
const bundlerAliasMap = {
"^@utils/(.*)$": "./src/utils/$1.js"
};
const resolveAlias = (specifier) => {
for (const [pattern, target] of Object.entries(bundlerAliasMap)) {
const regex = new RegExp(pattern);
if (regex.test(specifier)) {
return specifier.replace(regex, target);
}
}
return specifier;
};
const rewrittenSpecifier = resolveAlias("@utils/math");
assert.equal(rewrittenSpecifier, "./src/utils/math.js");
}
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"baseUrl": ".",
"paths": {
"@utils/*": ["src/utils/*"]
},
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"declaration": true,
"skipLibCheck": true
},
"include": ["src/**/*"]
}