From 07a0152b386c6728c59d4bc7fa1af686994d2fb0 Mon Sep 17 00:00:00 2001 From: Wahid Rizka Fathurrohman Date: Mon, 28 Sep 2026 10:17:50 +0700 Subject: [PATCH] Use exports for the default path when main is missing Without `path` in the config, Size Limit took `main` from package.json and otherwise `index.js`. An ESM-only package with only `exports`, like the one in #285, crashed with ENOENT on the missing `index.js`. Take the root entry of `exports` before falling back to `index.js`, preferring the `import` condition. --- fixtures/exports/lib/index.js | 1 + fixtures/exports/package.json | 20 ++++++++++++++++++++ packages/size-limit/get-config.js | 17 ++++++++++++++++- packages/size-limit/test/get-config.test.js | 15 +++++++++++++++ 4 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 fixtures/exports/lib/index.js create mode 100644 fixtures/exports/package.json diff --git a/fixtures/exports/lib/index.js b/fixtures/exports/lib/index.js new file mode 100644 index 00000000..41715495 --- /dev/null +++ b/fixtures/exports/lib/index.js @@ -0,0 +1 @@ +export const a = 1 diff --git a/fixtures/exports/package.json b/fixtures/exports/package.json new file mode 100644 index 00000000..ae0765ab --- /dev/null +++ b/fixtures/exports/package.json @@ -0,0 +1,20 @@ +{ + "name": "exports", + "private": true, + "type": "module", + "exports": { + ".": { + "import": "./lib/index.js" + } + }, + "devDependencies": { + "@size-limit/file": ">= 0.0.0", + "size-limit": ">= 0.0.0" + }, + "size-limit": [ + { + "name": "index", + "limit": "1 kB" + } + ] +} diff --git a/packages/size-limit/get-config.js b/packages/size-limit/get-config.js index 54e3541f..c290b667 100644 --- a/packages/size-limit/get-config.js +++ b/packages/size-limit/get-config.js @@ -99,6 +99,20 @@ function toAbsolute(file, cwd) { return isAbsolute(file) ? file : join(cwd, file) } +// The package root file from `exports`: the field itself when it is a string, +// otherwise its `.` entry, with conditions resolved in `import`, `default`, +// `require` order +function exportsEntry(exports) { + if (typeof exports === 'string') return exports + if (typeof exports !== 'object' || exports === null) return undefined + if ('.' in exports) return exportsEntry(exports['.']) + for (let condition of ['import', 'default', 'require']) { + let entry = exportsEntry(exports[condition]) + if (entry) return entry + } + return undefined +} + async function findFiles(patterns, cwd) { // Node.js `glob` matches a bare directory as a single entry, while // `tinyglobby` expanded it to the files inside. Add a `/**` sibling for @@ -205,7 +219,8 @@ export default async function getConfig(plugins, process, args, pkg) { require.resolve(join(dirname(pkg.path), pkg.packageJson.main)) ] } else { - processed.files = [join(dirname(pkg.path), 'index.js')] + let entry = exportsEntry(pkg.packageJson.exports) || 'index.js' + processed.files = [join(dirname(pkg.path), entry)] } } return processed diff --git a/packages/size-limit/test/get-config.test.js b/packages/size-limit/test/get-config.test.js index b157465a..c83234b7 100644 --- a/packages/size-limit/test/get-config.test.js +++ b/packages/size-limit/test/get-config.test.js @@ -111,6 +111,21 @@ it('uses index.js by default', async () => { }) }) +it('uses the root entry of exports without main field', async () => { + expect(await check('exports')).toEqual({ + checks: [ + { + files: [fixture('exports', 'lib', 'index.js')], + limit: '1 kB', + name: 'index', + sizeLimit: 1000 + } + ], + configPath: 'package.json', + cwd: fixture('exports') + }) +}) + it('overrides limit by CLI arg', async () => { expect(await check('simple', ['--limit', '10 kB'])).toEqual({ checks: [