notes/esbuild/README.md
esbuild resolver and transform behavior relevant to direct TypeScript execution.
esbuild tries an explicit path before extension candidates. When both value.js and value.ts exist, an explicit ./value.js resolves value.js. If value.js is absent, esbuild can fall back to value.ts through its TypeScript extension substitution (resolver).
For implicit candidates inside node_modules, esbuild prefers JavaScript over TypeScript. Its regression test locks the local TypeScript-first and dependency JavaScript-first difference. The 0.18.0 release notes explain that published packages can contain TypeScript that is not intended to execute.
esbuild distinguishes extension substitution from extension addition. It maps known JavaScript output extensions to TypeScript source extensions, while resolveExtensions handles appended candidates. An explicit asset.json wins over asset.json.js when it exists; a missing explicit asset can reach appended candidates (loadAsFile).
esbuild emits a dead-code module.exports annotation for certain transformed CommonJS export shapes. The annotation does not execute, but static CJS export lexers can recognize it (CommonJS linker output). This output shape is relevant to consumers that construct CJS namespaces from source text.