Skip to content

fix(devtools): keep hook statements in braceless bodies compiling - #9156

Open
Aejkatappaja wants to merge 5 commits into
QwikDev:mainfrom
Aejkatappaja:fix/devtools-braceless-hook-statement
Open

Aejkatappaja wants to merge 5 commits into
QwikDev:mainfrom
Aejkatappaja:fix/devtools-braceless-hook-statement

Conversation

@Aejkatappaja

Copy link
Copy Markdown
Member

Depends on #9153. This branch is stacked on it, so the first two commits are #9153's; only the last one is new here. I'll rebase once #9153 lands.

What is it?

  • Bug

Description

With DevTools or MCP enabled, a component that calls a hook as a statement in a braceless if, else or loop body stops compiling, or silently tracks the wrong thing:

if (props.flag) useLogger();
if (props.flag) useTask$(() => {});
else useTask$(() => {});
// before
if (props.flag) let _customhook_0 = useLogger(); collecthook({ ... });  // SyntaxError: let is not allowed here
if (props.flag) useTask$(() => {}); collecthook({ ... });                // runs even when flag is false
else useTask$(() => {}); ...                                             // SyntaxError: else no longer follows the if

// after
if (props.flag) { let _customhook_0 = useLogger(); collecthook({ ... }); }
if (props.flag) { useTask$(() => {}); collecthook({ ... }); }
else { useTask$(() => {}); collecthook({ ... }); }

When the statement's parent isn't a statement list (program, block, static block, case), the hook and its collecthook call now go in a block. Statements already in a block come out exactly as before, so the existing snapshot doesn't change.

While in there I switched the hook tracking to inserts only. A custom hook used to be rewritten with a replace of the whole statement, computed on the original text, so a hook called inside another hook's callback (if (c) useTask$(() => { useFoo(); });) produced broken output once the inner edit had shifted things. Inserting { let _customhook_0 = before the statement and ; collecthook(...) } after it never overlaps another edit. applySourceEdits also keeps inserts that share a position in the order they were added, otherwise useTask$(() => {});useLogger(); (no space) put the let in front of the previous collecthook and tracked its return value instead.

Not covered here: a hook in a var declaration directly in a braceless body (if (a) var v = useSignal(0);), and a hook in a for (...) header. Both were already broken and need the declaration path to know its grandparent, which I'd rather do separately.

Tests: the braceless if/else cases for custom and known hooks, a hook nested in another hook's callback, and adjacent statements. The output is parsed with oxc and must have no errors, and running the transform twice gives the same result.

Checklist

  • My code follows the developer guidelines of this project
  • I performed a self-review of my own code
  • I added a changeset with pnpm change
  • I added new tests to cover the fix / functionality

Tracking a hook called as the statement of a braceless if, else or loop body produced 'if (x) let ...' or put collecthook between the if and its else. Wrap the statement and its tracking in a block there, and track with inserts only so edits for nested hooks never overlap.
@changeset-bot

changeset-bot Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 33418db

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 8 packages
Name Type
@qwik.dev/devtools Patch
create-qwik Patch
eslint-plugin-qwik Patch
@qwik.dev/mcp Patch
@qwik.dev/react Patch
@qwik.dev/router Patch
@qwik.dev/utils Patch
@qwik.dev/core Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

@qwik.dev/core

npm i https://pkg.pr.new/QwikDev/qwik/@qwik.dev/core@9156

@qwik.dev/router

npm i https://pkg.pr.new/QwikDev/qwik/@qwik.dev/router@9156

@qwik.dev/utils

npm i https://pkg.pr.new/QwikDev/qwik/@qwik.dev/utils@9156

eslint-plugin-qwik

npm i https://pkg.pr.new/QwikDev/qwik/eslint-plugin-qwik@9156

create-qwik

npm i https://pkg.pr.new/QwikDev/qwik/create-qwik@9156

@qwik.dev/optimizer

npm i https://pkg.pr.new/QwikDev/qwik/@qwik.dev/optimizer@9156

@qwik.dev/devtools

npm i https://pkg.pr.new/QwikDev/qwik/@qwik.dev/devtools@9156

@qwik.dev/mcp

npm i https://pkg.pr.new/QwikDev/qwik/@qwik.dev/mcp@9156

commit: 33418db

@Aejkatappaja
Aejkatappaja marked this pull request as ready for review October 13, 2026 10:28
@Aejkatappaja
Aejkatappaja requested a review from a team as a code owner October 13, 2026 10:28

This branch has not been deployed

No deployments
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.

2 participants