Skip to content

fix(optimizer): skip null-valued exports in expandGlobIds glob resolution#22611

Open
LeSingh1 wants to merge 3 commits into
vitejs:mainfrom
LeSingh1:fix/optimize-deps-glob-null-exports
Open

fix(optimizer): skip null-valued exports in expandGlobIds glob resolution#22611
LeSingh1 wants to merge 3 commits into
vitejs:mainfrom
LeSingh1:fix/optimize-deps-glob-null-exports

Conversation

@LeSingh1
Copy link
Copy Markdown

@LeSingh1 LeSingh1 commented Jun 4, 2026

Fixes #22586.

When using glob patterns in optimizeDeps.include (e.g. my-pkg/*), Vite expands the pattern against the package's exports field. The non-glob path of that expansion unconditionally added every export key to the candidate list, including keys with a null value.

Per the Node.js docs, a null export value is how packages mark subpaths as intentionally private and unreachable:

To exclude private subfolders from patterns, null targets can be used.
https://nodejs.org/api/packages.html#subpath-patterns

For example, a package with this in its package.json:

{
  "exports": {
    ".": "./dist/index.js",
    "./utils": "./dist/utils.js",
    "./internal": null
  }
}

When a user adds "my-pkg/*" to optimizeDeps.include, the old code would include my-pkg/internal in the resolved list. Vite then tries to bundle that path, fails to find a file for it, and throws a build error.

The glob branch already handled this correctly by calling getFirstExportStringValue which returns undefined for null, triggering an early continue. The non-glob branch just needed the same null check.

The fix is a single guard in expandGlobIds inside packages/vite/src/node/optimizer/resolve.ts:

if (exports[key] === null) continue

A unit test is added that confirms null-valued export keys are excluded from the resolved list while non-null ones are still included.

LeSingh1 added 3 commits June 4, 2026 16:07
The previous test used vi.mock to stub resolvePackageData, but
vitest's isolate:false shares the module graph across test files.
By the time expandGlobIds.spec.ts runs, packages.ts is already
cached, so the mock never intercepts the real call and the function
returns [] early.

Replace the mock with a real temp-dir fixture: write an actual
package.json under a mkdtemp directory, point the config root there,
and let resolvePackageData resolve it naturally. Matches the pattern
used by other tests in this directory.
fs.mkdtempSync on macOS returns a path under /var/folders/... which is a
symlink to /private/var/folders/.... Vite's resolvePackageData uses realpaths
internally, so the fixture root mismatched and the test failed only on
node-24/macOS CI. Wrap mkdtempSync with fs.realpathSync to normalise the path.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

optimizeDeps.include glob should ignore null exports

1 participant