Skip to content

STRICT_READ_UNTRACKED is skipped during hydration and in lazy() component bodies #3675

Description

@brenelz

Describe the bug

In dev builds, STRICT_READ_UNTRACKED does not fire in two common cases, so the same component warns or stays silent depending on how the page was reached.

  1. Initial hydration. In read() (packages/signals/src/core/core.ts), the snapshotCaptureActive && c._config & CONFIG_IN_SNAPSHOT_SCOPE branch returns the snapshot value before the if (__DEV__ && strictRead) warnStrictReadUntracked(...) check. Component bodies that run during the first hydration pass never warn.
  2. lazy() components. lazy() (packages/solid/src/client/component.ts) renders the loaded component with untrack(() => Comp(props)) and no label. createComponent goes through observedComponent, which calls untrack(fn, "<Name>") and turns the check on. Reads in a lazy component's own body are never checked. File routes from @solidjs/router/fs are lazy(), so route components are affected. With solid-refresh enabled, client navigation still warns because the refresh proxy adds its own label, so this case shows up with hot: false or wherever refresh does not wrap the component.

The warning text also names only the scope (<Child>), not which value was read or where. Unnamed internal signals report as "signal" in the structured event.

Your Example Website or App

Minimal SSR app below (solid-js 2.0.0-rc.9, @solidjs/web 2.0.0-rc.9, @solidjs/router 2.0.0-next.30, @solidjs/vite-plugin 3.0.0-next.44 with ssr: true, start: { node: true }).

Steps to Reproduce the Bug or Issue

// App.tsx
import { createRouter } from "@solidjs/router";
import { createSignal, lazy } from "solid-js";

function Child(props: { count: () => number }) {
  const n = props.count();
  return <p>child body read {n}</p>;
}

function ChildPage() {
  const [count] = createSignal(1, { name: "count" });
  return <Child count={count} />;
}

const Router = createRouter({
  routes: [
    { path: "/", component: () => <p>home</p> },
    { path: "/child", component: ChildPage },
    { path: "/lazy", component: lazy(() => import("./LazyRoute")) },
  ],
});

export default function App() {
  return (
    <Router>
      {props => (
        <>
          <nav><a href="/">home</a> <a href="/child">child</a> <a href="/lazy">lazy</a></nav>
          {props.children}
        </>
      )}
    </Router>
  );
}

// LazyRoute.tsx
import { createSignal } from "solid-js";
export default function LazyRoute() {
  const [count] = createSignal(2, { name: "routeCount" });
  const n = count();
  return <p>lazy route body read {n}</p>;
}
  1. Run the dev server and open /child directly (fresh SSR load). No warning.
  2. Open /, then click the child link. STRICT_READ_UNTRACKED ... in <Child> is logged.
  3. Same for /lazy: a fresh load is silent. With solid({ hot: false }), client navigation to /lazy is silent as well.

Console results in Chromium (Playwright), stock rc.9:

Case Warnings
fresh load /child 0
fresh load /lazy 0
client nav to /child 1
client nav to /lazy (solid-refresh on) 1
client nav to /lazy (hot: false) 0

Expected behavior

As a user, I expected a component body that reads a signal directly to warn every time it runs in dev, whether it runs during hydration, after client navigation, or inside a lazy() component. Right now it only warns after client navigation or an HMR update, which is also when developers are least likely to be looking at a fresh console.

It would also help if the console line said which value was read and where, for example read of "count" at Child (App.tsx:5:13).

Platform

  • OS: macOS
  • Browser: Chromium (Playwright 1.62)
  • Version: solid-js 2.0.0-rc.9, @solidjs/signals 2.0.0-rc.9

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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions