Skip to content

@void/react: a non-island component under an _-prefixed directory in pages/ ships every page module to the browser #575

Open

Description

@gopalpatel

Version: void / @void/react 1.2.1 (also 1.1.12); main at a6de782.

Repro

  1. pnpm create void (React, static output: output: 'static' in void.config.ts).
  2. pages/index.island.tsx:
    import { Frame } from './_ui/frame';
    export default function Home() { return <Frame><h1>Hello</h1></Frame>; }
  3. pages/_ui/frame.tsx, a shared server-only component that is not a page or an island:
    export const SECRET_COPY = 'server-only text';
    export function Frame({ children }: { children: React.ReactNode }) {
      return <main data-x={SECRET_COPY}>{children}</main>;
    }
  4. vp build, then ls dist/client/assets and grep -l 'server-only text' dist/client/assets/*.js.

Expected: an island-only app emits no pages-client bundle, and frame.tsx (not a route, because the route scanner skips _ segments) never reaches dist/client.

Actual: pages-client-*.js plus a chunk for every page module and every import (frame-*.js) are emitted to dist/client/assets, and the server-only strings are in them. In our app that is 18 files and 351 KB instead of 5 files and 33 KB, and 42 strings that were meant to stay server-side.

Cause: packages/react/src/plugin-pages.ts hasNonIslandPages() skips only basenames that start with _:

if (name.startsWith('_') || name.startsWith('layout.')) continue;

entry.name for pages/_ui/frame.tsx is frame.tsx. The pages scanner (scan.ts) skips any segment that starts with _ (except _layouts), so the two disagree. The Solid plugin has the same check.

Suggested fix: test every path segment relative to dir, as the scanner does:

const rel = relative(dir, join(entry.parentPath, name));
if (rel.split(sep).some((s) => s.startsWith('_')) || name.startsWith('layout.')) continue;

This is adjacent to #559, which adds the .server. exclusion to the same line.

Activity

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

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions