Skip to content

An import spelled with a trailing slash or a ./ segment loses its lazy-component and file-import edges #2577

Closed

Description

@inth3shadows

Summary

A JS/TS import whose specifier ends in a slash, like import('@/widgets/Chart/'), or carries a . segment, like src/widgets/./Chart, loses the edges the plain spelling gets. The lazy-loaded component is no longer linked, and App gets a calls edge to its own Chart const instead. A named import from the same specifier still resolves.

Reproduction (verified)

On main at c71a3d0, built from source, Linux (WSL2), Node 22.22.2. The project has two files, plus a package.json with react:

// src/App.tsx   (SPEC is one of the three spellings below)
import { lazy } from 'react';
import { Legend } from 'SPEC';
const Chart = lazy(() => import('SPEC'));
export function App() { Legend(); return <Chart />; }
// src/widgets/Chart/index.tsx
export default function ChartView() { return null; }
export function Legend() { return 1; }

Edges out of src/App.tsx after CodeGraph.init(dir, { index: true }), excluding contains:

SPEC lazy component file import
@/widgets/Chart App -calls-> src/widgets/Chart/index.tsx::ChartView App.tsx -imports-> src/widgets/Chart/index.tsx
@/widgets/Chart/ App -calls-> src/App.tsx::Chart missing
src/widgets/./Chart App -calls-> src/App.tsx::Chart missing

App -calls-> src/widgets/Chart/index.tsx::Legend and App.tsx -imports-> …::Legend are present in all three rows.

Likely cause (inferred from reading the code)

fileExists falls back to fs.existsSync, which accepts src/widgets/Chart//index.tsx and src/widgets/./Chart/index.tsx. The import resolver's alias and bare-path branches (for example resolveAliasedImport) join the specifier as written and return that spelling. Lookups keyed by the indexed path, such as getNodesInFile or a files row, then miss. Normalizing the path once, at resolveImportPath's return or in fileExists, would fix every caller.

Such a path also reaches synthesis_inputs, whose file_path references files(path) (#2565). #2574 normalizes on that one write, but the resolver still returns the raw spelling.

Related

Not checked

Windows, macOS (case-insensitive paths), and tsconfig paths aliases. The @/ above goes through the fallback alias, with no tsconfig in the project. From reading the code, the relative and tsconfig-paths branches normalize, but I have not tested that.

Activity

  1. colbymchenry commented on Oct 22, 2026

    @colbymchenry
    Owner

    Thanks for the precise report and for tracing it to the resolver's path handling.

    #2792 is merged to main. An import spelled with a trailing slash, a ./ or ../ segment, or a doubled slash now links like the plain spelling:

    • the file import comes back;
    • its names resolve through the import;
    • a lazily loaded component points at the component the file exports.

    That holds for the @/ fallback, direct src/… paths and workspace packages. A trailing slash still names a folder, so @/widgets/Chart/ resolves to Chart/index.tsx, as Node and tsc read it. The fix ships in the next release.

  2. added a commit that references this issue on Oct 22, 2026
    8651990
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions