diff --git a/packages/core/src/config.ts b/packages/core/src/config.ts index c458fafd1..b79a86973 100644 --- a/packages/core/src/config.ts +++ b/packages/core/src/config.ts @@ -63,6 +63,7 @@ import { calcLongestCommonPath, checkMFPlugin, getAbsolutePath, + isDirectory, isEmptyObject, isIntermediateOutputFormat, isObject, @@ -1436,6 +1437,19 @@ const composeBundlelessExternalConfig = ( } else { // 1. js files hit JS_EXTENSIONS_PATTERN,./foo ->./foo.mjs if (jsRedirectExtension) { + // If the import path refers to a directory, + // it most likely actually refers to a `index.*` file due to Node's module resolution. + // When redirect.js.path is set to false, index should still be added before adding extension. + // When redirect.js.path is true, the resolver directly generate correct resolvedRequest with index appended. + if ( + !jsRedirectPath && + (await isDirectory( + join(dirname(issuer), resolvedRequest), + )) + ) { + // This uses `/` instead of `path.join` here because `join` removes potential "./" prefixes + resolvedRequest = `${resolvedRequest.replace(/\/+$/, '')}/index`; + } resolvedRequest = `${resolvedRequest}${jsExtension}`; } } diff --git a/packages/core/src/utils/helper.ts b/packages/core/src/utils/helper.ts index b6eed58f8..952b017e5 100644 --- a/packages/core/src/utils/helper.ts +++ b/packages/core/src/utils/helper.ts @@ -246,3 +246,12 @@ const windowsSlashRegex = /\\/g; export function normalizeSlash(p: string): string { return p.replace(windowsSlashRegex, '/'); } + +export async function isDirectory(filePath: string): Promise { + try { + const stat = await fsP.stat(filePath); + return stat.isDirectory(); + } catch { + return false; + } +} diff --git a/tests/integration/redirect/js.test.ts b/tests/integration/redirect/js.test.ts index dd02e1753..e14780749 100644 --- a/tests/integration/redirect/js.test.ts +++ b/tests/integration/redirect/js.test.ts @@ -53,11 +53,11 @@ test('redirect.js.path false', async () => { import { bar } from "@/bar"; import { foo } from "@/foo"; import { baz } from "~/baz"; - import { bar as external_bar_js_bar } from "./bar.js"; + import { bar as index_js_bar } from "./bar/index.js"; import { foo as external_foo_js_foo } from "./foo.js"; export * from "./.hidden.js"; - export * from "./.hidden-folder.js"; - const src = lodash.toUpper(lodash_merge(external_foo_js_foo) + external_bar_js_bar + foo + bar + baz + typeof prettier.version); + export * from "./.hidden-folder/index.js"; + const src = lodash.toUpper(lodash_merge(external_foo_js_foo) + index_js_bar + foo + bar + baz + typeof prettier.version); export { src as default }; " `);