Repository navigation
Description
On vitejs/vite @ 8492422, indexed at b9ca4b7, 157 cross-file imports edge rows resolve onto a single non-exported local variable.
Every import { defineConfig } from 'vite' across the playground and create-vite templates lands on:
playground/ssr-html/test-stacktrace.js::vite
which is this, at module scope in a file that exports nothing at all:
import { createServer } from 'vite'
// ...
const vite = await createServer({ /* ... */ })The correct target is the workspace member packages/vite ("name": "vite", exports["."] = "./dist/node/index.js"), which is in the graph.
Counts
| rows | |
|---|---|
edges targeting a node named vite |
317 |
— contains (a file holding its own vite node; not at issue) |
159 |
— imports, same-file |
1 |
— imports, cross-file |
157 |
| distinct targets among those 157 | 1 |
source files importing from 'vite' |
148 / 148 |
Why the existing guards do not catch it
matchByExactName filters candidates to non-import nodes that are lexically reachable, and commits when exactly one survives. Here one does — the module-level const — so the reference resolves with resolvedBy: 'exact-match' and confidence 0.9.
The bare-import guards do not apply, and correctly so. packages/vite/package.json declares the name vite and pnpm-workspace.yaml globs packages/*, so resolveWorkspaceImport('vite', …) reports the specifier project-local and isBoundToBareImport returns false. The specifier really is project-local; the failure is that the name then matches any node called vite rather than the member's entry.
Measured, on this corpus against the same merge base:
- fix(resolution): an out-of-repo import doesn't hide a same-file nested declaration #1715 removes 0 of the 157. I built its head (
eb9fddf) and indexed: 2,487 edge rows removed, none of them these. Its guard is right and simply does not reach this case. - fix(resolution): a name bound to a bare import resolves to no project node #1713 removes 0.
- The markdown-index change (feat(explore): markdown index (#361) with a section-first doc tier #1699) removes 60 of the 157 — by accident, not by design. Indexing 84 more files adds two more nodes named
vite, the single-survivor branch stops firing for those references, and they decline. 97 still resolve wrongly afterwards.
Two places a fix could go, and I do not have a view on which
- Export visibility. A module-level binding that the file does not export is not reachable by an import from another file.
isLexicallyReachableadmits it today. This looks like the general defect — it is not specific to workspace packages, and any non-exported top-level name is a candidate for any same-named import anywhere. - Workspace package resolution. When a specifier resolves to a workspace member, the target should be that member's entry point rather than a name lookup.
entryByNamealready exists for the ArkTS case.
(1) is the broader fix and would subsume this; (2) is narrower and would leave the same shape wherever a package is not a workspace member.
Reproduction
git clone https://github.com/vitejs/vite && cd vite && git checkout 8492422
codegraph init && codegraph index .Then query the graph for imports edges whose target node is named vite and whose source file differs from the target's file.
Kernel rebuilt from source per arm; index db copied out before reading. Edge rows counted with multiplicity, keyed by source, target and kind — a distinct count reads lower because one source line can carry two genuine references at different columns.
Activity
docs(readme): the bare-`vite` class is 157 rows, and the fork fixes 6…
bompus commentedon Sep 6, 2026
Opened #1720 with the narrower of the two framings — not the workspace one, and not quite the export-visibility one either.
The rule there is per-FILE rather than per-symbol: a JS/TS file with an
importand no export of any form offers nothing to any other file. That avoids the two false-positive classes a per-symbolisExportedtest would hit (a laterexport { x }, and CommonJS), since neither sets the flag on the node.Measured on the same corpus and merge base: 320 rows removed, all 320 verified to land on a file that exports nothing, and 18 rows added that the patch is responsible for. The additions and a rejected stricter variant are written up in the PR rather than left out.
docs(readme): the bare-`vite` class has a fix now, and it is not one …
test(resolution): bind the colbymchenry#1719 fixture without a bare i…
colbymchenry commentedon Sep 8, 2026
Fixed in #1746.
That PR lands @bompus’s sealed-module guard from #1720 onto current
main(after #1745). #1745’s file-local visibility correctly reported LOST 0 / GAINED 0 on vite JS/TS and does not cover this case; the sealed-module rule does.Verified on Linux:
main, the An import of a workspace package resolves onto a non-exported local variable of the same name (157 edges in vitejs/vite) #1719 regression (widgetreached from another file) failsBindings in a module that exports nothing (#1719)8/8 pass, and fix(resolution): a definition its language makes file-local is not a cross-file target (#1731) #1745’scross-file-visibilitysuite still 11/11 passClosing as fixed by #1746 (also
Fixes #1719on the PR for merge auto-close).fix(resolution): a binding in a module that exports nothing is not a …
fix(resolution): a receiver-less JS/TS call never binds to a method (#…
fix(resolution): a reference that spells out a Markdown file still re…
fix(resolution): a reference that spells out a Markdown file still re…
perf(resolution): remove the indexing regressions since v1.6.0 (vscod…
fix(resolution): a reference that spells out a Markdown file still re…