Skip to content

extension: fixes and improvements for the Chrome extension #356

Description

@erkamyaman

Context

Fixes and improvements from a code audit of the chrome extension, done in October 2026. Roadmap work lives in #340, #341, #342 and #343. Items marked (to confirm) were not reproduced; check them before fixing.

Problems

Medium

  • Only one trusted extension ID: the server trusts a single ID (packages/devtools/src/extension-origin.ts:5) and the panel pins a single origin string (extension/panel-bridge.js:21). Edge Add-ons does not keep the manifest key, so a published Edge build gets a 403 from every hub until each user adds allowedOrigins. Add the Edge ID to PANGULAR_EXTENSION_IDS once the listing exists, and generate PINNED_ORIGIN from the same list so both sides change together.

Low

  • Server search runs one probe at a time: findConnection awaits each fetch in turn, with a 1.5 s timeout each. With 7 candidates after dedupe, a missing or hung server shows "Detecting Angular app…" for about 10 s, plus a fixed 500 ms delay at start and 1000 ms after each navigation. Fire the probes together with Promise.allSettled and pick the first success in PATHS order, and drop the fixed delays (extension/panel-bridge.js:133-159, 219, 224).
  • Angular inside iframes is never found: detection, the page id lookup and $0 lookups call inspectedWindow.eval without frameURL, and the server is searched on the top frame's origin. Storybook, micro-frontend shells and embedded previews never connect. When the top frame has no Angular, find the frames and pass frameURL (extension/devtools.js:28, extension/panel-bridge.js:53-58, 72).
  • Worker tab map is lost when Chrome stops the worker: angularTabs lives in memory, so the fast path in devtools.js usually misses (its own comment says so), and the is-angular-page handler returns true after a synchronous sendResponse. Once the content scripts go (phase 1 of 4: safe by default and wired into your workflow #340), remove the worker; if it stays, keep the map in chrome.storage.session and drop return true (extension/background.js:2, 26, extension/devtools.js:9).
  • Granted hosts cannot be seen or removed: there is no options_ui and no chrome.permissions.remove call, and the privacy policy sends users to Chrome's site settings. Add a small options page, or a link in the status view, that lists granted origins outside the loopback set with a Remove button (extension/manifest.json, extension/panel-bridge.js).
  • Extension version is bumped by hand: extension/manifest.json and packages/devtools/package.json:3 are both 0.0.7, but nothing keeps them in sync and scripts/extension-zip.mjs does not check it. Make the zip script set or verify the manifest version from the package version.
  • No end-to-end test loads the real extension: the packages/devtools/src/__tests__/extension-*.test.ts tests all stub chrome.*, and ci.yml only checks that extension/ui is not stale. A manifest mistake or a Chrome API change would ship unnoticed. Add a Playwright job that runs Chromium with --load-extension=extension against the demo SSR app and checks that the panel loads ui/index.html with a pageId.

Improvements

  • Toolbar icon (chrome.action) that turns colored on Angular pages, with a small popup showing the Angular version, dev or prod mode and whether a Pangular server answered. Use activeTab so it adds no install warning (extension/manifest.json, new popup files).
  • Elements sidebar pane through chrome.devtools.panels.elements.createSidebarPane that shows the selected element's component inputs and signals (extension/devtools.js, extension/panel-bridge.js).
  • Keep the UI iframe across navigations: today every network.onNavigated reloads the whole panel. Only search for the server again when the origin changes, so the tab, filter and selection survive a reload (extension/panel-bridge.js:221-225, 182-190).
  • Remember the last base path that worked for each origin (sessionStorage in the panel) and try it first, so reconnecting is close to instant (extension/panel-bridge.js).
  • Standalone mode: when no Pangular server answers, read the page directly through inspectedWindow.eval and the in-page collectors, giving read-only component, signal and DI views with no server setup (extension/panel-bridge.js, app/src/extension-bridge.ts).
  • Audit the extension panel with axe: extend scripts/panel-axe.mjs to load extension/panel.html with a stubbed chrome object, so the status view is checked too. test:axe only audits dist/panel-axe today (package.json:19).
  • CI release job that runs extension:zip on tags and attaches the zip to the GitHub release, so users can load a downloaded build without cloning (.github/workflows, scripts/extension-zip.mjs).

Already tracked elsewhere


Generated by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken or shows wrong datafeatureA feature request or a pull request that adds one

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions