Skip to content

defineModuleConfig: Pages/Index.tsx silently breaks builds on case-insensitive filesystems #131

@antosubash

Description

@antosubash

A module whose only page is Pages/Index.tsx (with the framework-required Pages/index.ts barrel doing () => import('./Index')) builds a broken bundle on macOS/Windows.

Repro (macOS or Windows)

  1. Module with single page Pages/Index.tsx and barrel Pages/index.ts:
    export const pages = { 'Foo/Index': () => import('./Index') };
  2. vite build succeeds, no warnings.
  3. The lazy chunk emitted (Index-<hash>.mjs) contains the barrel's content (~94 bytes), not the React component:
    var pages = { "Foo/Index": () => import("./Index-<hash>.mjs") };
    export { pages };
    (recursive self-import)
  4. Runtime: TypeError: Cannot assign to property 'layout' of [object Module] from resolveLayout — the lazy import returned the frozen entry namespace, not a component module.

Cause

Rolldown resolves import('./Index') to ./index.ts (the entry) on case-insensitive filesystems. The build silently produces a duplicated chunk. Workaround in consumer code is import('./Index.tsx') with explicit extension.

Fix options

  1. defineModuleConfig rejects this combination at config-evaluation time with a clear error.
  2. Auto-rewrite extension-less imports inside Pages/index.ts (similar to TypeScript module: "node16").
  3. Rename the framework barrel to something that can't collide (e.g. Pages/_pages.ts).

The natural pattern for any module's "home" page IS Pages/Index.tsx, so this trap will catch every new framework adopter on Mac/Windows.

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