Skip to content

[explorer] add local explorer hotkey to the vite plugin#13137

Draft
emily-shen wants to merge 3 commits intomainfrom
emily/vite-hotkey
Draft

[explorer] add local explorer hotkey to the vite plugin#13137
emily-shen wants to merge 3 commits intomainfrom
emily/vite-hotkey

Conversation

@emily-shen
Copy link
Copy Markdown
Contributor

@emily-shen emily-shen commented Mar 31, 2026

this uses e like in wrangler, which doesn't conflict with any default vite hotkeys.

vite doesn't have a way of hiding bindings, so this should not be merged until we are ready to properly announce this.

Also, we seem to use open in c3 and wrangler to open browsers, so i've used it here too in the vite plugin, and added it to the pnpm catalog and updated the version from 8 -> 11. open v11 is ESM only, but it seems fine? I vaguely remember we have tried to move off as many CJS packages as possible, not sure if this was skipped on purpose.


  • Tests
    • Tests included/updated
    • Automated tests not possible - manual testing has been completed as follows:
    • Additional testing not necessary because:
  • Public documentation
    • Cloudflare docs PR(s):
    • Documentation not necessary because:

A picture of a cute animal (not mandatory, but encouraged)


Open with Devin

@emily-shen emily-shen requested a review from a team as a code owner March 31, 2026 08:48
@emily-shen emily-shen requested a review from ascorbic March 31, 2026 08:48
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 31, 2026

🦋 Changeset detected

Latest commit: 0e4fb82

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

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

@workers-devprod
Copy link
Copy Markdown
Contributor

workers-devprod commented Mar 31, 2026

Codeowners approval required for this PR:

  • ✅ @cloudflare/wrangler
Show detailed file reviewers

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 31, 2026

✅ All changesets look good

@emily-shen emily-shen added the blocked Blocked on other work label Mar 31, 2026
@ask-bonk
Copy link
Copy Markdown
Contributor

ask-bonk bot commented Mar 31, 2026

I've now thoroughly reviewed all the changes. Let me summarize my findings:

The implementation is clean and follows existing patterns well. The code:

  1. Correctly mirrors wrangler's e hotkey implementation from packages/wrangler/src/dev/hotkeys.ts
  2. Uses CorePaths.EXPLORER constant properly
  3. Has proper TTY guard matching the bindings shortcut pattern
  4. Handles resolvedUrls being undefined gracefully
  5. Properly handles the open() error case (matching wrangler's pattern, but with a more helpful error message that includes the URL)
  6. The open dependency is correctly placed in devDependencies since tsdown bundles it
  7. The catalog entry for open is properly added to pnpm-workspace.yaml and existing open deps in create-cloudflare and wrangler are migrated to use it
  8. Tests are well-structured
  9. The changeset is properly formatted

The only thing I notice is not really an issue but worth noting: in wrangler, the explorer hotkey has its label intentionally hidden (commented out) to keep it secret before announcement, while the vite plugin has a visible description: "open local explorer". But the PR description explicitly notes "this should not be merged until we are ready to properly announce this," so this is intentional.

LGTM

github run

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 4 additional findings.

Open in Devin Review

@emily-shen emily-shen marked this pull request as draft March 31, 2026 08:59
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Mar 31, 2026

create-cloudflare

npm i https://pkg.pr.new/create-cloudflare@13137

@cloudflare/kv-asset-handler

npm i https://pkg.pr.new/@cloudflare/kv-asset-handler@13137

miniflare

npm i https://pkg.pr.new/miniflare@13137

@cloudflare/pages-shared

npm i https://pkg.pr.new/@cloudflare/pages-shared@13137

@cloudflare/unenv-preset

npm i https://pkg.pr.new/@cloudflare/unenv-preset@13137

@cloudflare/vite-plugin

npm i https://pkg.pr.new/@cloudflare/vite-plugin@13137

@cloudflare/vitest-pool-workers

npm i https://pkg.pr.new/@cloudflare/vitest-pool-workers@13137

@cloudflare/workers-editor-shared

npm i https://pkg.pr.new/@cloudflare/workers-editor-shared@13137

wrangler

npm i https://pkg.pr.new/wrangler@13137

commit: 0e4fb82

@emily-shen emily-shen marked this pull request as ready for review March 31, 2026 10:08
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 new potential issue.

View 5 additional findings in Devin Review.

Open in Devin Review

Comment on lines +170 to +172
server.bindCLIShortcuts({
customShortcuts: [openExplorerShortcut],
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔴 addExplorerShortcut chains through addBindingsShortcut wrapper, calling original bindCLIShortcuts with only the explorer shortcut

When both addBindingsShortcut and addExplorerShortcut are called sequentially (as in configureServer at packages/vite-plugin-cloudflare/src/plugins/shortcuts.ts:26-27 and configurePreviewServer at lines 35-36), the explorer function's call to server.bindCLIShortcuts({ customShortcuts: [openExplorerShortcut] }) at line 170-172 chains through the bindings wrapper (installed at line 88-110) which forwards the call to Vite's original bindCLIShortcuts with only [openExplorerShortcut]. If Vite's bindCLIShortcuts replaces (rather than accumulates) custom shortcuts on each invocation, the previously registered bindings shortcut (b) is lost. The fix is to either register both shortcuts in a single call, or have each wrapper merge its own shortcut into the customShortcuts array before forwarding.

Trace of the call chain
  1. addBindingsShortcut wraps original and calls: origBind({ customShortcuts: [b] })
  2. addExplorerShortcut wraps the bindings wrapper and calls: explorerWrapper({ customShortcuts: [e] })bindingsWrapper({ customShortcuts: [e] })origBind({ customShortcuts: [e] })

The [b] shortcut from step 1 is not included in step 2's call to the original.

Prompt for agents
In packages/vite-plugin-cloudflare/src/plugins/shortcuts.ts, the addExplorerShortcut function (lines 118-173) and addBindingsShortcut function (lines 41-116) each independently wrap server.bindCLIShortcuts and call it with their own shortcut. When addExplorerShortcut chains through addBindingsShortcut's wrapper, the original bindCLIShortcuts is called with only the explorer shortcut, potentially losing the bindings shortcut.

The recommended fix is to have the wrapper functions merge their own shortcuts into any customShortcuts that are passed through. Specifically, in each wrapper (lines 88-110 and lines 148-168), before calling the saved bindCLIShortcuts, merge the plugin's own shortcut into options.customShortcuts. For example, change the bindings wrapper to:

  bindCLIShortcuts({
    ...options,
    customShortcuts: [
      ...(options?.customShortcuts ?? []),
      printBindingsShortcut,
    ],
  });

And similarly for the explorer wrapper. Then change the final call in each function from server.bindCLIShortcuts({ customShortcuts: [shortcut] }) to just server.bindCLIShortcuts() (or server.bindCLIShortcuts({})), so the wrapper itself injects the shortcut.

Alternatively, combine both shortcuts into a single registration function that calls server.bindCLIShortcuts once with both customShortcuts.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +136 to +142
const childProcess = await open(explorerUrl);
childProcess.on("error", () => {
viteServer.config.logger.warn(
"Failed to open browser, the local explorer can be accessed at " +
explorerUrl
);
});
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Just as a sanity check: There's no additional process cleanup needed for this, correct? It's just cleaned up / killed once it's out of scope.

@github-project-automation github-project-automation bot moved this from Untriaged to Approved in workers-sdk Mar 31, 2026
@petebacondarwin petebacondarwin marked this pull request as draft March 31, 2026 13:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

blocked Blocked on other work

Projects

Status: Approved

Development

Successfully merging this pull request may close these issues.

3 participants