diff --git a/src/index.js b/src/index.js index 78a9d9db..636d03a1 100644 --- a/src/index.js +++ b/src/index.js @@ -258,6 +258,21 @@ function ncc ( })); } + const tsCompilerOptions = { + module: 'esnext', + target: 'esnext', + ...fullTsconfig.compilerOptions, + allowSyntheticDefaultImports: true, + noEmit: false, + outDir: '//' + }; + + if (esm && emitsNonEsmModule(tsCompilerOptions.module)) { + // ESM builds need TypeScript to preserve imports so webpack can resolve + // dependencies with "import" conditions instead of "require" conditions. + tsCompilerOptions.module = 'esnext'; + } + const compiler = webpack({ entry, cache: cache === false ? undefined : { @@ -365,14 +380,7 @@ function ncc ( options: { transpileOnly, compiler: eval('__dirname + "/typescript.js"'), - compilerOptions: { - module: 'esnext', - target: 'esnext', - ...fullTsconfig.compilerOptions, - allowSyntheticDefaultImports: true, - noEmit: false, - outDir: '//' - } + compilerOptions: tsCompilerOptions } }] }, @@ -635,6 +643,17 @@ function ncc ( } } +function emitsNonEsmModule(moduleKind) { + if (typeof moduleKind === 'string') { + return ['commonjs', 'amd', 'umd', 'system'].includes(moduleKind.toLowerCase()); + } + + // Values match TypeScript's ModuleKind enum: + // CommonJS=1, AMD=2, UMD=3, System=4. + // https://github.com/microsoft/TypeScript/blob/v5.2.2/src/compiler/types.ts#L7255-L7260 + return moduleKind >= 1 && moduleKind <= 4; +} + // this could be rewritten with actual FS apis / globs, but this is simpler function getFlatFiles(mfsData, output, getAssetMeta, tsconfig, curBase = "") { for (const path of Object.keys(mfsData)) { diff --git a/test/unit/ts-esm-import-condition/input.ts b/test/unit/ts-esm-import-condition/input.ts new file mode 100644 index 00000000..0ccbf64c --- /dev/null +++ b/test/unit/ts-esm-import-condition/input.ts @@ -0,0 +1,3 @@ +import { value } from 'esm-only-condition-package'; + +console.log(value); diff --git a/test/unit/ts-esm-import-condition/node_modules/esm-only-condition-package/index.d.ts b/test/unit/ts-esm-import-condition/node_modules/esm-only-condition-package/index.d.ts new file mode 100644 index 00000000..a5987fbd --- /dev/null +++ b/test/unit/ts-esm-import-condition/node_modules/esm-only-condition-package/index.d.ts @@ -0,0 +1 @@ +export declare const value: string; diff --git a/test/unit/ts-esm-import-condition/node_modules/esm-only-condition-package/index.js b/test/unit/ts-esm-import-condition/node_modules/esm-only-condition-package/index.js new file mode 100644 index 00000000..f02f7dbc --- /dev/null +++ b/test/unit/ts-esm-import-condition/node_modules/esm-only-condition-package/index.js @@ -0,0 +1 @@ +export const value = 'from-esm-only-package'; diff --git a/test/unit/ts-esm-import-condition/node_modules/esm-only-condition-package/package.json b/test/unit/ts-esm-import-condition/node_modules/esm-only-condition-package/package.json new file mode 100644 index 00000000..95c48dc2 --- /dev/null +++ b/test/unit/ts-esm-import-condition/node_modules/esm-only-condition-package/package.json @@ -0,0 +1,12 @@ +{ + "name": "esm-only-condition-package", + "version": "1.0.0", + "type": "module", + "types": "./index.d.ts", + "exports": { + ".": { + "types": "./index.d.ts", + "import": "./index.js" + } + } +} diff --git a/test/unit/ts-esm-import-condition/opt.json b/test/unit/ts-esm-import-condition/opt.json new file mode 100644 index 00000000..a63f21dd --- /dev/null +++ b/test/unit/ts-esm-import-condition/opt.json @@ -0,0 +1,3 @@ +{ + "esm": true +} diff --git a/test/unit/ts-esm-import-condition/output-coverage.js b/test/unit/ts-esm-import-condition/output-coverage.js new file mode 100644 index 00000000..ac1139e1 --- /dev/null +++ b/test/unit/ts-esm-import-condition/output-coverage.js @@ -0,0 +1,13 @@ +/******/ /* webpack/runtime/compat */ +/******/ +/******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = new URL('.', import.meta.url).pathname.slice(import.meta.url.match(/^file:\/\/\/\w:/) ? 1 : 0, -1) + "/"; +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; + +;// CONCATENATED MODULE: ./test/unit/ts-esm-import-condition/node_modules/esm-only-condition-package/index.js +const value = 'from-esm-only-package'; + +;// CONCATENATED MODULE: ./test/unit/ts-esm-import-condition/input.ts + +console.log(value); diff --git a/test/unit/ts-esm-import-condition/output.js b/test/unit/ts-esm-import-condition/output.js new file mode 100644 index 00000000..ac1139e1 --- /dev/null +++ b/test/unit/ts-esm-import-condition/output.js @@ -0,0 +1,13 @@ +/******/ /* webpack/runtime/compat */ +/******/ +/******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = new URL('.', import.meta.url).pathname.slice(import.meta.url.match(/^file:\/\/\/\w:/) ? 1 : 0, -1) + "/"; +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; + +;// CONCATENATED MODULE: ./test/unit/ts-esm-import-condition/node_modules/esm-only-condition-package/index.js +const value = 'from-esm-only-package'; + +;// CONCATENATED MODULE: ./test/unit/ts-esm-import-condition/input.ts + +console.log(value); diff --git a/test/unit/ts-esm-import-condition/tsconfig.json b/test/unit/ts-esm-import-condition/tsconfig.json new file mode 100644 index 00000000..e8073242 --- /dev/null +++ b/test/unit/ts-esm-import-condition/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "module": "commonjs", + "moduleResolution": "node", + "target": "es2020" + } +}