feat(extension): add browser extension package with Chrome MV3 and Firefox MV2#97
Open
Aejkatappaja wants to merge 8 commits intoQwikDev:mainfrom
Open
feat(extension): add browser extension package with Chrome MV3 and Firefox MV2#97Aejkatappaja wants to merge 8 commits intoQwikDev:mainfrom
Aejkatappaja wants to merge 8 commits intoQwikDev:mainfrom
Conversation
…refox MV2 New packages/browser-extension package using WXT framework. Includes content script with Qwik detection, SPA navigation tracking, element picker with main-world click interception, background relay, and DevTools panel entry points. Supports Chrome MV3 and Firefox MV2.
Add hookRuntime.ts that installs window.__QWIK_DEVTOOLS_HOOK__ with signal inspection, component snapshots, state editing, and render event tracking. Add vnodeBridge.ts that traverses the VNode tree using Qwik internal APIs and pushes real-time updates via MutationObserver. Bridge render events from perfRuntime via postMessage for extension consumption.
Add PageDataSource interface abstracting page data access for both overlay (direct window) and extension (inspectedWindow.eval) modes. Add RemotePageDataSource with VNode bridge injection via dynamic import, package detection from container attributes, Vite plugin detection, and render event subscription. Add QwikDevtoolsExtension component and CSR entry point for the extension panel.
Full component tree panel reusing Tree, RenderTreeTabs, and HookFiltersCard from the overlay. Features: real-time updates via subscribeTreeUpdates, SPA navigation handling with treeVersion key, name-based fingerprint to skip redundant re-renders, element picker integration, hover highlight via hook.highlightNode, expand/collapse toggle, inline signal editing, and data-node-id attributes on tree rows for reliable hover targeting.
…ents Adapt Overview for extension mode: hide pages/assets cards, show packages from container attributes, Vite plugin detection banner. Add live render events to Performance tab with SSR+CSR seed data. Gray out Vite-only tabs with placeholder messages. Add shared IconButton, InfoBanner components and IconTarget, IconExpandShrink, IconMonitor, IconInfoCircle icons. Fix HookFiltersCard grid overflow.
Add devtools-hook.js injected by content script for hook installation without the Vite plugin. Add vnode-bridge.js as ES module fallback. VNode bridge is also installed via inspectedWindow.eval with dynamic import that reuses the page's cached Qwik core module URL from performance entries. Extension now works on any Qwik dev site.
31 tests for hookTreeHelpers (toTreeNodes, treeIdFingerprint, findNodeById, findNodeByDomAttr, getElementType, valueToTree, buildDetailTree) and 8 tests for isExtensionMessage type guard.
🦋 Changeset detectedLatest commit: 5ec219e The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Browser extension (Chrome/Firefox) that brings Qwik DevTools to the browser's DevTools panel, following the same architecture as Vue DevTools: extension for runtime features, Vite overlay for server features.
The extension shares the UI components with the existing in-app overlay and works both with and without the
qwikDevtools()Vite plugin.Quick Demo
CleanShot.2026-04-10.at.3.28.18.mp4
What's implemented
Component Tree (real-time)
@qwik.dev/core/internalAPIsq:idinstead of sequential countersPAGE_CHANGEDTree,RenderTreeTabs,HookFiltersCardcomponentsState inspection
Element picker
inspect-hook.jsintercepts clicks before qwikloaderdata-qwik-inspector+ VNode mapHover highlight
hook.highlightNode(nodeId)which walks VNode to first DOM elementdata-node-idattributes on tree rows for reliable targetingLive render events
perfRuntimevia postMessageRENDER_EVENTto panel__QWIK_PERF__snapshot (SSR + CSR)Performance & Preloads
__QWIK_PERF__and__QWIK_PRELOADS__viainspectedWindow.eval()Overview
q:containerHTML attributes (q:version)Standalone mode (without Vite plugin)
devtools-hook.js(plain script, no imports)inspectedWindow.eval()with dynamicimport()performance.getEntriesByType('resource')to reuse cached module (no duplicate Qwik instance)qwikDevtools()in vite.configVite-only tabs
Shared components
IconButton- toolbar button with icon slot and active stateInfoBanner- contextual info message with iconIconTarget,IconExpandShrink,IconMonitor,IconInfoCircleadded to IconsTests
Architecture
What works per mode
What's NOT in this PR (follow-up work)
Production support
The VNode bridge uses
import('@qwik.dev/core/internal')which only resolves in dev mode (Vite serves bare imports). In production, the Qwik core is bundled and minified, internal APIs aren't accessible. This requires either:<script type="qwik/vnode">directlySignals without Vite plugin
QWIK_DEVTOOLS_GLOBAL_STATEis populated by the plugin's component instrumentation. Without it, signals live in closures inside components and can't be accessed externally. Requires Qwik core to register signals on the hook whenuseSignal()is called (same as Vue's approach).Both items above are best addressed after the devtools repo moves into the Qwik monorepo, where internal APIs can be tightly coupled (as discussed in the RFC thread).
Testing
Load the Chrome extension from
packages/browser-extension/.output/chrome-mv3/viachrome://extensions(developer mode).Load the Firefox extension from
packages/browser-extension/.output/firefox-mv2/viaabout:debugging.