fix: preserve TypeScript imports for ESM builds#1319
Conversation
| return ['commonjs', 'amd', 'umd', 'system'].includes(module.toLowerCase()); | ||
| } | ||
|
|
||
| return module >= 1 && module <= 4; |
There was a problem hiding this comment.
Where are these integers defined? Lets link to the docs so its clear.
There was a problem hiding this comment.
Ah yeah, that’s fair. I added a link to the TypeScript enum here and renamed the helper so it’s clearer what those numbers are doing.
| } | ||
|
|
||
| async function expectEsmOnlyTypeScriptBuild(compilerOptions) { | ||
| const testDir = fs.mkdtempSync(path.join(__dirname, "tmp-esm-ts-cjs-")); |
There was a problem hiding this comment.
Why is this a temp directory? Looks like you're building a test fixture so lets just create a new test fixture and commit it since this doesn't need any dynamic behavior
There was a problem hiding this comment.
Youre right that makes more sense, just changed it. Thanks!!
df63d25 to
7b6fccb
Compare
| @@ -0,0 +1,7 @@ | |||
| { | |||
| "compilerOptions": { | |||
| "module": "commonjs", | |||
There was a problem hiding this comment.
This is super strange behavior since you have module=commonjs in tsconfig.json here but type=module in package.json
Does this code even compile and run using tsc + node?
I dont understand why ncc should support this 🤔
There was a problem hiding this comment.
No you’re so right, the fixture makes the case look a bit weird.
I was trying to test ncc’s ESM output path instaed of saying that this setup should be run directly with tsc + Node. Lemme clean it up by moving the import-only package into node_modules and making esm: true explicit in the fixture options so the test is clearer.
Summary
tsconfig.jsonasks TypeScript to emit a known CommonJS-style module formatimportconditionFixes #1311.
Why
@actions/core@3.0.0is ESM-only: its package root hastype: "module"and anexports["."].importentry, but norequirecondition. In a TypeScript project withtype: "module"andcompilerOptions.moduleset toCommonJS, ncc correctly selects ESM output, but ts-loader lowers the entry import torequire(). Webpack then resolves the dependency through CommonJS conditions and fails withPackage path . is not exported.The fixture sets
esm: trueexplicitly so the test focuses on ncc's ESM output path while keeping the TypeScriptmodule: "commonjs"setting that triggers the regression.This patch keeps TypeScript imports intact only for that ESM-output/CommonJS-emit mismatch, so webpack can resolve import-only packages through their
importcondition without broadening the behavior for CJS ncc builds.Research / Repro
@actions/core@3.0.0exposes package root throughimportonly vianpm view @actions/core@3.0.0 version type exports --json.compilerOptions.module: "CommonJS"toModuleKind.CommonJS, which is the known CommonJS-style emit mode covered here.origin/mainin a detached worktree: it fails withPackage path . is not exportedfor an import-only package.Testing
./node_modules/.bin/tsc --noEmit -p test/unit/ts-esm-import-condition/tsconfig.jsonnode --expose-gc --max_old_space_size=4096 node_modules/jest/bin/jest.js test/unit.test.js --runInBand --testNamePattern ts-esm-import-conditionnode --expose-gc --max_old_space_size=4096 node_modules/jest/bin/jest.js test/unit.test.js --runInBand --coverage --globals '{"coverage":true}' --testNamePattern ts-esm-import-condition