From 8a2a39a3b9de46689dcc442ba737d6b3cab1d2cb Mon Sep 17 00:00:00 2001 From: Deepak Singh Date: Fri, 10 Apr 2026 08:07:43 +0000 Subject: [PATCH 1/2] feat: support adding .js extensions to subpath exports (closes #898) --- src/features/pkg/exports.test.ts | 24 ++++++++++++++++++++++++ src/features/pkg/exports.ts | 29 +++++++++++++++++++++-------- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/src/features/pkg/exports.test.ts b/src/features/pkg/exports.test.ts index c9841dd11..41e3f715e 100644 --- a/src/features/pkg/exports.test.ts +++ b/src/features/pkg/exports.test.ts @@ -899,6 +899,30 @@ describe('generateExports', () => { } `) }) + + test('subpathExtension', async ({ expect }) => { + const results = generateExports( + { es: [genChunk('index.js'), genChunk('foo.js')] }, + { + exports: { subpathExtension: true }, + }, + ) + await expect(results).resolves.toMatchInlineSnapshot(` + { + "bin": undefined, + "exports": { + ".": "./index.js", + "./foo.js": "./foo.js", + "./package.json": "./package.json", + }, + "inlinedDependencies": undefined, + "main": undefined, + "module": undefined, + "publishExports": undefined, + "types": undefined, + } + `) + }) }) function genChunk( diff --git a/src/features/pkg/exports.ts b/src/features/pkg/exports.ts index 08da58600..eef1f09c1 100644 --- a/src/features/pkg/exports.ts +++ b/src/features/pkg/exports.ts @@ -112,6 +112,12 @@ export interface ExportsOptions { * bin: { tool: './src/cli-tool.ts' } */ bin?: boolean | string | Record + + /** + * Add .js extension to all subpath exports. + * @default false + */ + subpathExtension?: boolean } export async function writeExports( @@ -187,6 +193,7 @@ export async function generateExports( legacy, inlinedDependencies: emitInlinedDeps = true, bin, + subpathExtension, }, css, logger, @@ -291,10 +298,13 @@ export async function generateExports( ) let exports: Record = Object.fromEntries( - sortedExportsMap.map(([name, subExport]) => [ - name, - genSubExport(devExports, subExport), - ]), + sortedExportsMap.map(([name, subExport]) => { + let finalName = name + if (subpathExtension && name !== '.' && !/\.[^/]+$/.test(name)) { + finalName = `${name}.js` + } + return [finalName, genSubExport(devExports, subExport)] + }), ) exportMeta(exports, all, packageJson) exportCss(exports, chunks, css, pkgRoot) @@ -311,10 +321,13 @@ export async function generateExports( let publishExports: Record | undefined if (devExports) { publishExports = Object.fromEntries( - sortedExportsMap.map(([name, subExport]) => [ - name, - genSubExport(false, subExport), - ]), + sortedExportsMap.map(([name, subExport]) => { + let finalName = name + if (subpathExtension && name !== '.' && !/\.[^/]+$/.test(name)) { + finalName = `${name}.js` + } + return [finalName, genSubExport(false, subExport)] + }), ) exportMeta(publishExports, all, packageJson) exportCss(publishExports, chunks, css, pkgRoot) From 33a85fe1e8de330c3da58adf8dffa56702179963 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Fri, 10 Apr 2026 08:09:10 +0000 Subject: [PATCH 2/2] [autofix.ci] apply automated fixes --- dts.snapshot.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dts.snapshot.json b/dts.snapshot.json index 3f72b9e53..5b20c2809 100644 --- a/dts.snapshot.json +++ b/dts.snapshot.json @@ -143,7 +143,7 @@ "DevtoolsOptions": "interface DevtoolsOptions extends NonNullable {\n ui?: boolean | Partial\n clean?: boolean\n}", "DtsOptions": "interface DtsOptions extends Options$1 {\n cjsReexport?: boolean\n}", "ExeOptions": "interface ExeOptions extends ExeExtensionOptions {\n seaConfig?: Omit\n fileName?: string | ((_: RolldownChunk) => string)\n outDir?: string\n}", - "ExportsOptions": "interface ExportsOptions {\n devExports?: boolean | string\n packageJson?: boolean\n all?: boolean\n exclude?: (RegExp | string)[]\n legacy?: boolean\n customExports?: Record | ((_: Record, _: { pkg: PackageJson; chunks: ChunksByFormat; isPublish: boolean }) => Awaitable>)\n inlinedDependencies?: boolean\n bin?: boolean | string | Record\n}", + "ExportsOptions": "interface ExportsOptions {\n devExports?: boolean | string\n packageJson?: boolean\n all?: boolean\n exclude?: (RegExp | string)[]\n legacy?: boolean\n customExports?: Record | ((_: Record, _: { pkg: PackageJson; chunks: ChunksByFormat; isPublish: boolean }) => Awaitable>)\n inlinedDependencies?: boolean\n bin?: boolean | string | Record\n subpathExtension?: boolean\n}", "Format": "type Format = ModuleFormat", "InlineConfig": "interface InlineConfig extends UserConfig {\n config?: boolean | string\n configLoader?: 'auto' | 'native' | 'unrun'\n filter?: RegExp | Arrayable\n}", "NoExternalFn": "type NoExternalFn = (_: string, _: string | undefined) => boolean | null | undefined | void",