Skip to content

fix(devtools): rename Solid use* primitives to create* for React Compiler compat#477

Merged
AlemTuzlak merged 3 commits into
mainfrom
fix/devtools-solid-hook-naming
Jun 24, 2026
Merged

fix(devtools): rename Solid use* primitives to create* for React Compiler compat#477
AlemTuzlak merged 3 commits into
mainfrom
fix/devtools-solid-hook-naming

Conversation

@AlemTuzlak

@AlemTuzlak AlemTuzlak commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

Problem

The devtools packages are written in Solid, but their custom primitives used React-style use* naming (useStyles, useTheme, useDevtoolsState, …). When a consuming app enables React Compiler, the compiler matches the use* naming convention and transforms/optimizes this Solid code as if it were React hooks — which breaks the panel, because it's Solid JSX, not React.

Change

Rename every custom Solid primitive across the three Solid packages from use*create*, and import the framework use* primitives under non-use aliases so the compiler no longer flags them:

  • 15 primitives renamed (definitions + all call sites, incl. cross-package imports): useStylescreateStyles, useThemecreateTheme, useDevtoolsContext/useDevtoolsState/useDevtoolsSettings/usePlugins/usePersistOpen/useHeight, useDraw/useDrawContext, usePiPWindow, useHeadChanges, useDisableTabbing, useAllyValue/useAllyContext.
  • Solid's useContext → imported as getContext (couldn't reuse createContext — it's a separate Solid export already imported in the same files).
  • @solid-primitives/keyboard's useKeyDownList → imported as getKeyDownList (same compiler risk).

Breaking change

  • @tanstack/devtools-ui (minor): the exported useTheme is renamed to createTheme. All other renames are internal (not part of any package's public entry).

Verification

  • nx build ✅ all 7 affected packages (build emits .d.ts via tsc, so types are clean)
  • nx test:lib ✅ all three packages
  • nx test:eslint ✅ all three packages

Changeset included.

Summary by CodeRabbit

  • New Features

    • Added factory-style create* APIs for theming, styles, context, settings, state, and hotkeys across the devtools and UI packages.
  • Bug Fixes

    • Improved accessibility panel export to generate downloads on demand (JSON/CSV) and handle missing audit results gracefully.
  • Breaking Changes

    • useThemecreateTheme.
    • Solid “primitive” and devtools APIs renamed from use*create* (including useStyles, usePlugins, useDevtoolsState, useDevtoolsSettings, usePersistOpen, useHeight, useDrawContext, usePiPWindow, and useHeadChanges).

…iler compat

The devtools packages are Solid but used React-style naming (useStyles,
useTheme, useDevtoolsState, ...) for their custom primitives. When an app
enables React Compiler, it matches the use* convention and transforms this
Solid code as if it were React, breaking the panel.

Rename every custom Solid primitive in @tanstack/devtools, devtools-ui, and
devtools-a11y from use* to create*, and import Solid's useContext and
@solid-primitives' useKeyDownList under non-use aliases (getContext,
getKeyDownList).

BREAKING(@tanstack/devtools-ui): exported useTheme is renamed to createTheme.
@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b7db9540-82b8-4d5d-81de-3bc7569d296a

📥 Commits

Reviewing files that changed from the base of the PR and between 0022e02 and acd92d4.

📒 Files selected for processing (8)
  • packages/devtools-ui/src/components/checkbox.tsx
  • packages/devtools/skills/devtools-plugin-panel/SKILL.md
  • packages/devtools/skills/devtools-plugin-panel/references/panel-api.md
  • packages/devtools/src/components/content-panel.tsx
  • packages/devtools/src/components/main-panel.tsx
  • packages/devtools/src/components/tabs.test.tsx
  • packages/devtools/src/components/tabs.tsx
  • packages/devtools/src/tabs/settings-tab.test.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/devtools/src/components/main-panel.tsx
  • packages/devtools/src/components/tabs.tsx
  • packages/devtools-ui/src/components/checkbox.tsx
  • packages/devtools/src/components/content-panel.tsx

📝 Walkthrough

Walkthrough

Solid theme, context, styles, and helper APIs are renamed from use* to create* across the devtools packages. All consuming components, tabs, tests, and docs are updated to use the renamed exports.

Changes

Solid use* → create* Primitive Rename

Layer / File(s) Summary
Changeset and docs
packages/devtools/skills/devtools-plugin-panel/SKILL.md, packages/devtools/skills/devtools-plugin-panel/references/panel-api.md, .changeset/solid-hook-naming-react-compiler.md
The changeset records the rename and package bumps, and the plugin-panel guidance/API reference update their createTheme examples and export listings.
Context and theme entry points
packages/devtools-ui/src/components/theme.tsx, packages/devtools-ui/src/index.ts, packages/devtools/src/context/use-devtools-context.ts, packages/devtools/src/context/draw-context.tsx, packages/devtools/src/context/pip-context.tsx, packages/devtools-a11y/src/core/contexts/allyContext.tsx
useTheme, useDevtoolsContext, usePlugins, useDevtoolsState, useDevtoolsSettings, usePersistOpen, useHeight, useDrawContext, usePiPWindow, and useAllyContext are renamed to create* exports, with useContext aliased as getContext in the context files.
Styles factories
packages/devtools-ui/src/styles/use-styles.ts, packages/devtools/src/styles/use-styles.ts, packages/devtools-a11y/src/core/styles/styles.ts
useStyles is renamed to createStyles in all three style factories, and each now sources theme from createTheme().
Utility hook renames
packages/devtools/src/hooks/use-disable-tabbing.ts, packages/devtools/src/hooks/use-head-changes.ts
useDisableTabbing becomes createDisableTabbing, and useHeadChanges becomes createHeadChanges.
devtools-ui consumers
packages/devtools-ui/src/components/button.tsx, packages/devtools-ui/src/components/checkbox.tsx, packages/devtools-ui/src/components/header.tsx, packages/devtools-ui/src/components/input.tsx, packages/devtools-ui/src/components/logo.tsx, packages/devtools-ui/src/components/main-panel.tsx, packages/devtools-ui/src/components/section.tsx, packages/devtools-ui/src/components/select.tsx, packages/devtools-ui/src/components/tag.tsx, packages/devtools-ui/src/components/tree.tsx
The devtools-ui components switch their styling setup from useStyles() to createStyles().
devtools components and tabs
packages/devtools/src/devtools.tsx, packages/devtools/src/components/*, packages/devtools/src/tabs/*, packages/devtools/src/components/tabs.test.tsx, packages/devtools/src/tabs/settings-tab.test.tsx
Devtools components and tabs switch to the renamed create* helpers for settings, state, height, PiP, draw context, styles, plugins, theme, and head-change handling; SourceInspector also aliases useKeyDownList as getKeyDownList, and the tab tests update their store access.
devtools-a11y consumers
packages/devtools-a11y/src/core/components/IssueCard.tsx, packages/devtools-a11y/src/core/components/IssueList.tsx, packages/devtools-a11y/src/core/components/Settings.tsx, packages/devtools-a11y/src/core/components/Shell.tsx
The a11y components switch from useStyles/useAllyContext to createStyles/createAllyContext, and Shell updates its export flow to gate on allyResult.audit and import exportAuditResults dynamically.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 Hop, hop, the hooks all changed their names,
create* now lights the Solid flame.
Themes and styles in tidy trails,
No hook-shaped compile-time snags nor fails.
The rabbit nods: “same hops, new lanes!”

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed It clearly states the core change: renaming Solid use* primitives to create* for React Compiler compatibility.
Description check ✅ Passed It covers the problem, rename scope, breaking change, and verification, though it doesn't follow the repo's exact template headings.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/devtools-solid-hook-naming

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@nx-cloud

nx-cloud Bot commented Jun 24, 2026

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit 0022e02

Command Status Duration Result
nx run-many --targets=build --exclude=examples/... ✅ Succeeded 36s View ↗

☁️ Nx Cloud last updated this comment at 2026-06-24 10:41:35 UTC

@nx-cloud

nx-cloud Bot commented Jun 24, 2026

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit 0022e02

Command Status Duration Result
nx affected --targets=test:eslint,test:sherif,t... ✅ Succeeded 12s View ↗

☁️ Nx Cloud last updated this comment at 2026-06-24 10:58:27 UTC

@pkg-pr-new

pkg-pr-new Bot commented Jun 24, 2026

Copy link
Copy Markdown
More templates

@tanstack/angular-devtools

npm i https://pkg.pr.new/@tanstack/angular-devtools@477

@tanstack/devtools

npm i https://pkg.pr.new/@tanstack/devtools@477

@tanstack/devtools-a11y

npm i https://pkg.pr.new/@tanstack/devtools-a11y@477

@tanstack/devtools-client

npm i https://pkg.pr.new/@tanstack/devtools-client@477

@tanstack/devtools-ui

npm i https://pkg.pr.new/@tanstack/devtools-ui@477

@tanstack/devtools-utils

npm i https://pkg.pr.new/@tanstack/devtools-utils@477

@tanstack/devtools-vite

npm i https://pkg.pr.new/@tanstack/devtools-vite@477

@tanstack/devtools-event-bus

npm i https://pkg.pr.new/@tanstack/devtools-event-bus@477

@tanstack/devtools-event-client

npm i https://pkg.pr.new/@tanstack/devtools-event-client@477

@tanstack/preact-devtools

npm i https://pkg.pr.new/@tanstack/preact-devtools@477

@tanstack/react-devtools

npm i https://pkg.pr.new/@tanstack/react-devtools@477

@tanstack/solid-devtools

npm i https://pkg.pr.new/@tanstack/solid-devtools@477

@tanstack/svelte-devtools

npm i https://pkg.pr.new/@tanstack/svelte-devtools@477

@tanstack/vue-devtools

npm i https://pkg.pr.new/@tanstack/vue-devtools@477

commit: acd92d4

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/devtools-a11y/src/core/components/Shell.tsx (1)

22-29: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Invert the handleExport guard.

Line 23 returns when allyResult.audit exists, so both export buttons become no-ops in the only state where they are shown. It also leaves Line 28 dereferencing allyResult.audit! on the no-audit path.

Suggested fix
   const handleExport = (format: 'json' | 'csv') => {
-    if (allyResult.audit) return
+    if (!allyResult.audit) return
     // Keep export logic in runtime via event -> overlay? export is still a direct helper.
     // We keep this import local to avoid pulling export code into the runtime module.

     void import('../utils/export-audit.uitls').then((m) =>
       m.exportAuditResults(allyResult.audit!, { format }),
     )
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/devtools-a11y/src/core/components/Shell.tsx` around lines 22 - 29,
The handleExport guard in Shell.tsx is inverted, causing exports to exit when
allyResult.audit exists and leaving exportAuditResults to dereference
allyResult.audit! when it is absent. Update handleExport so it only returns
early when there is no audit result, then pass the existing audit value into
exportAuditResults after the local import resolves, keeping the behavior aligned
with the export buttons.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/devtools/src/components/tabs.tsx`:
- Around line 18-21: The PiP feature string built in handleDetachment is
malformed because the left value includes an extra closing brace, which can
cause the window position to be ignored. Update the requestPipWindow argument in
tabs.tsx to remove the stray character and ensure the width, height, top, and
left entries are formatted consistently.

In `@packages/devtools/src/context/use-devtools-context.ts`:
- Around line 8-16: Update the JSDoc on createDevtoolsContext so it accurately
describes DevtoolsContext and its store/setStore API instead of ShellContext
state/setState, and change the missing-provider error message to reference the
correct DevtoolsContextProvider rather than ShellContextProvider. Keep the
wording aligned with the actual symbols in use (createDevtoolsContext,
DevtoolsContext, store, setStore) so the generated docs and runtime hint match
the implementation.

---

Outside diff comments:
In `@packages/devtools-a11y/src/core/components/Shell.tsx`:
- Around line 22-29: The handleExport guard in Shell.tsx is inverted, causing
exports to exit when allyResult.audit exists and leaving exportAuditResults to
dereference allyResult.audit! when it is absent. Update handleExport so it only
returns early when there is no audit result, then pass the existing audit value
into exportAuditResults after the local import resolves, keeping the behavior
aligned with the export buttons.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0c7e946c-c2b4-4128-9a8a-5a2a51a3b541

📥 Commits

Reviewing files that changed from the base of the PR and between 7114ecd and 0022e02.

📒 Files selected for processing (45)
  • .changeset/solid-hook-naming-react-compiler.md
  • packages/devtools-a11y/src/core/components/IssueCard.tsx
  • packages/devtools-a11y/src/core/components/IssueList.tsx
  • packages/devtools-a11y/src/core/components/Settings.tsx
  • packages/devtools-a11y/src/core/components/Shell.tsx
  • packages/devtools-a11y/src/core/contexts/allyContext.tsx
  • packages/devtools-a11y/src/core/styles/styles.ts
  • packages/devtools-ui/src/components/button.tsx
  • packages/devtools-ui/src/components/checkbox.tsx
  • packages/devtools-ui/src/components/header.tsx
  • packages/devtools-ui/src/components/input.tsx
  • packages/devtools-ui/src/components/logo.tsx
  • packages/devtools-ui/src/components/main-panel.tsx
  • packages/devtools-ui/src/components/section.tsx
  • packages/devtools-ui/src/components/select.tsx
  • packages/devtools-ui/src/components/tag.tsx
  • packages/devtools-ui/src/components/theme.tsx
  • packages/devtools-ui/src/components/tree.tsx
  • packages/devtools-ui/src/index.ts
  • packages/devtools-ui/src/styles/use-styles.ts
  • packages/devtools/src/components/content-panel.tsx
  • packages/devtools/src/components/main-panel.tsx
  • packages/devtools/src/components/source-inspector.tsx
  • packages/devtools/src/components/tab-content.tsx
  • packages/devtools/src/components/tabs.tsx
  • packages/devtools/src/components/trigger.tsx
  • packages/devtools/src/context/draw-context.tsx
  • packages/devtools/src/context/pip-context.tsx
  • packages/devtools/src/context/use-devtools-context.ts
  • packages/devtools/src/devtools.tsx
  • packages/devtools/src/hooks/use-disable-tabbing.ts
  • packages/devtools/src/hooks/use-head-changes.ts
  • packages/devtools/src/styles/use-styles.ts
  • packages/devtools/src/tabs/hotkey-config.tsx
  • packages/devtools/src/tabs/marketplace/marketplace-header.tsx
  • packages/devtools/src/tabs/marketplace/plugin-card.tsx
  • packages/devtools/src/tabs/marketplace/plugin-section.tsx
  • packages/devtools/src/tabs/marketplace/settings-panel.tsx
  • packages/devtools/src/tabs/marketplace/tag-filters.tsx
  • packages/devtools/src/tabs/plugin-marketplace.tsx
  • packages/devtools/src/tabs/plugins-tab.tsx
  • packages/devtools/src/tabs/seo-tab/index.tsx
  • packages/devtools/src/tabs/seo-tab/serp-preview.tsx
  • packages/devtools/src/tabs/seo-tab/social-previews.tsx
  • packages/devtools/src/tabs/settings-tab.tsx

Comment on lines 18 to 21
const handleDetachment = () => {
pipWindow().requestPipWindow(
`width=${window.innerWidth},height=${state().height},top=${window.screen.height},left=${window.screenLeft}}`,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Remove the stray } from the PiP feature string.

Line 20 builds left=${window.screenLeft}}, which makes the features string malformed. That can cause the left position to be ignored when the detached window opens.

Suggested fix
   const handleDetachment = () => {
     pipWindow().requestPipWindow(
-      `width=${window.innerWidth},height=${state().height},top=${window.screen.height},left=${window.screenLeft}}`,
+      `width=${window.innerWidth},height=${state().height},top=${window.screen.height},left=${window.screenLeft}`,
     )
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleDetachment = () => {
pipWindow().requestPipWindow(
`width=${window.innerWidth},height=${state().height},top=${window.screen.height},left=${window.screenLeft}}`,
)
const handleDetachment = () => {
pipWindow().requestPipWindow(
`width=${window.innerWidth},height=${state().height},top=${window.screen.height},left=${window.screenLeft}`,
)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/devtools/src/components/tabs.tsx` around lines 18 - 21, The PiP
feature string built in handleDetachment is malformed because the left value
includes an extra closing brace, which can cause the window position to be
ignored. Update the requestPipWindow argument in tabs.tsx to remove the stray
character and ensure the width, height, top, and left entries are formatted
consistently.

Comment on lines 8 to +16
/**
* Returns an object containing the current state and setState function of the ShellContext.
* Throws an error if used outside of a ShellContextProvider.
*/
const useDevtoolsContext = () => {
const context = useContext(DevtoolsContext)
const createDevtoolsContext = () => {
const context = getContext(DevtoolsContext)
if (context === undefined) {
throw new Error(
'useDevtoolsShellContext must be used within a ShellContextProvider',
'createDevtoolsContext must be used within a ShellContextProvider',

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the stale context docs and provider hint.

This helper reads DevtoolsContext, which exposes store/setStore, but the JSDoc still documents state/setState from ShellContext, and Line 16 still tells callers to use ShellContextProvider. That will publish incorrect docs and mislead anyone debugging a missing-provider failure.

As per coding guidelines, JSDoc should read like documentation as it gets converted to markdown docs for the website.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/devtools/src/context/use-devtools-context.ts` around lines 8 - 16,
Update the JSDoc on createDevtoolsContext so it accurately describes
DevtoolsContext and its store/setStore API instead of ShellContext
state/setState, and change the missing-provider error message to reference the
correct DevtoolsContextProvider rather than ShellContextProvider. Keep the
wording aligned with the actual symbols in use (createDevtoolsContext,
DevtoolsContext, store, setStore) so the generated docs and runtime hint match
the implementation.

Source: Coding guidelines

#472 added component tests (tabs.test.tsx, settings-tab.test.tsx) using the
old useDevtoolsState/useDevtoolsSettings names, and the devtools-plugin-panel
skill docs referenced the renamed devtools-ui export useTheme. Update them to
the create* names.
@AlemTuzlak AlemTuzlak merged commit ea3c674 into main Jun 24, 2026
15 of 16 checks passed
@AlemTuzlak AlemTuzlak deleted the fix/devtools-solid-hook-naming branch June 24, 2026 11:04
@github-actions github-actions Bot mentioned this pull request Jun 24, 2026
AlemTuzlak added a commit that referenced this pull request Jun 24, 2026
nx.json sets `parallel: 5`, which is fine for local dev machines but
oversubscribes GitHub-hosted runners: each affected `test:lib` (vitest) and
`test:types` (tsc) task spawns its own worker pool, so 5 heavy tasks at once
exhaust CPU/RAM and intermittently stall or OOM-kill deterministic tasks. That
produced flaky failures across unrelated PRs (#471, #477, #478) that pass on a
plain re-run.

The team already pins `test:e2e` to `--parallel=1` for the same reason; cap the
Test job's nx parallelism via NX_PARALLEL=3 (CI-only, leaves local dev at 5).
Combined with the raised vitest timeouts, this keeps tasks within the runner's
budget.
AlemTuzlak added a commit that referenced this pull request Jun 24, 2026
…uts) (#478)

* test(devtools): raise vitest timeouts to stop flaky component test:lib in CI

The component tests added in #472 render the full Solid + goober tree and take
1-4s locally. Shared CI runners are ~4x slower (the suite runs in ~8s locally
but ~31s in CI), which pushes individual tests past vitest's default 5s
testTimeout and causes intermittent `@tanstack/devtools:test:lib` failures
across unrelated PRs (e.g. #471, #477).

Raise testTimeout and hookTimeout to 30s for the devtools package so slow CI
runs have headroom. Fast unit tests are unaffected; a real hang still fails
(just after 30s instead of 5s).

* ci: cap nx parallelism to 3 to fix flaky Test job

nx.json sets `parallel: 5`, which is fine for local dev machines but
oversubscribes GitHub-hosted runners: each affected `test:lib` (vitest) and
`test:types` (tsc) task spawns its own worker pool, so 5 heavy tasks at once
exhaust CPU/RAM and intermittently stall or OOM-kill deterministic tasks. That
produced flaky failures across unrelated PRs (#471, #477, #478) that pass on a
plain re-run.

The team already pins `test:e2e` to `--parallel=1` for the same reason; cap the
Test job's nx parallelism via NX_PARALLEL=3 (CI-only, leaves local dev at 5).
Combined with the raised vitest timeouts, this keeps tasks within the runner's
budget.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant