experiment(widgets): embeddable same-document Query editor widget - #71089
experiment(widgets): embeddable same-document Query editor widget#71089mariusandra wants to merge 1 commit into
Conversation
New standalone 'widgets' entry that exposes window.PostHogWidgets.mountQueryEditor: the real editable Query/InsightViz editor (series, taxonomic pickers, breakdown, date range, chart type) mounted into a foreign document with its own React 18 + kea inside a shadow root — the toolbar pattern, but for the insight editor. - frontend/src/widgets/: mount API, shadow-root component (FloatingContainerContext keeps popovers/tooltips/modals inside the shadow root; [theme] attribute drives dark mode), tiny instance store for handle.update(), harness page. - Auth: reuses the standalone OAuth mode in lib/api. setOAuthSessionOverride() seeds an IN-MEMORY session (host apiHost + bearer token, host-provided refresh callback) instead of localStorage, so host tokens never persist. - vite.widgets.config.mts builds dist-widgets/widgets.js (ESM + lazy chunks) and widgets.css, linked into the shadow root at runtime; bin/serve-widgets.mjs serves it with CORS for cross-origin module loading. - __unsafeMockContext option seeds userLogic/teamLogic for credential-less harness testing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🤖 CI report✅ Bundle size — 🟢 -118.7 KiB (-0.2%)Uncompressed size of every built Total: 64.69 MiB · 🟢 -118.7 KiB (-0.2%)
Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report ✅ Eager graph — within budgetHow much code each root ships on the eager path — downloaded and parsed before the surface is interactive. Measured from the esbuild output chunks (post-tree-shake, static imports only); lazy
🟢 Largest files eagerly shipped from
|
| Size | File |
|---|---|
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 24.6 KiB | ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js |
| 6.3 KiB | ../node_modules/.pnpm/react@18.3.1/node_modules/react/cjs/react.production.min.js |
| 4.5 KiB | ../node_modules/.pnpm/@jspm+core@2.1.0/node_modules/@jspm/core/nodelibs/browser/process.js |
| 3.9 KiB | ../node_modules/.pnpm/scheduler@0.23.2/node_modules/scheduler/cjs/scheduler.production.min.js |
| 1.4 KiB | ../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js |
| 1.3 KiB | src/RootErrorBoundary.tsx |
| 912 B | ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js |
| 789 B | src/scenes/ChunkLoadErrorBoundary.tsx |
| 762 B | src/index.tsx |
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
| Size | File |
|---|---|
| 281.5 KiB | ../node_modules/.pnpm/posthog-js@1.407.2/node_modules/posthog-js/dist/rrweb.js |
| 267.7 KiB | ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 236.0 KiB | src/taxonomy/core-filter-definitions-by-group.json |
| 226.1 KiB | ../node_modules/.pnpm/posthog-js@1.407.2/node_modules/posthog-js/dist/module.js |
| 167.1 KiB | src/queries/validators.js |
| 154.3 KiB | ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js |
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 105.8 KiB | src/lib/api.ts |
| 94.0 KiB | ../packages/quill/packages/quill/dist/index.js |
| 93.3 KiB | ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js |
Posted automatically by check-eager-graph · sizes are eager output bytes (shipped, post-tree-shake) from the esbuild metafile · part of #32479
⚠️ Dist folder size — 🔺 +43.54 MiB (+3.3%)
Total size of the built frontend/dist folder (all assets), compared against the base branch.
Total: 1358.73 MiB · 🔺 +43.54 MiB (+3.3%)
✅ toolbar-size — eager 2.18 MiB within budget
What the toolbar ships to customer pages, measured from the esbuild output (minified, post-tree-shake). The eager set is the entry plus everything statically imported from it — fetched before any feature runs; deferred chunks load lazily. The eager guardrail is 5.72 MiB. Each output file must also stay below 10 MB, where CloudFront stops compressing it. The module boundary is enforced separately by check-toolbar-graph.
| Metric | Size | Δ vs base | Budget |
|---|---|---|---|
| Eager (shipped) entry + static imports |
2.18 MiB · 17 files | (no base measurement) | ████░░░░░░ 38.1% of 5.72 MiB |
| Deferred (lazy) | 2.07 MiB · 33 files | (no base measurement) | n/a — loads on demand |
Loader dist/toolbar.js |
1.1 KiB | (no base measurement) | █░░░░░░░░░ 5.8% of 19.5 KiB |
Largest eagerly-shipped chunks
| Size | File |
|---|---|
| 713.9 KiB | dist/toolbar/toolbar-app-LCNSOSSY.css |
| 545.1 KiB | dist/toolbar/chunk-chunk-QLM5HYJB.js |
| 484.2 KiB | dist/toolbar/chunk-chunk-JSRFT4OP.js |
| 133.6 KiB | dist/toolbar/chunk-chunk-N4Y5SKCH.js |
| 131.8 KiB | dist/toolbar/chunk-chunk-T5KY5WYR.js |
| 71.0 KiB | dist/toolbar/toolbar-app-2N3ASZ4F.js |
| 69.0 KiB | dist/toolbar/chunk-chunk-27JL52RE.js |
| 35.6 KiB | dist/toolbar/chunk-chunk-G6GTV2WP.js |
| 20.9 KiB | dist/toolbar/chunk-chunk-46QHR4PU.js |
| 12.2 KiB | dist/toolbar/chunk-chunk-PIK3PADE.js |
Posted automatically by check-toolbar-size · sizes are toolbar output bytes (shipped, post-tree-shake) from the esbuild metafile
|
This PR hasn't seen activity in a week! Should it be merged, closed, or further worked on? If you want to keep it open, please remove the |
|
Merging to
After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here |
|
This PR hasn't seen activity in a week! Should it be merged, closed, or further worked on? If you want to keep it open, please remove the |
|
This PR was closed due to lack of activity. Feel free to reopen if it's still relevant. |
Experiment:
widgetsentry — mount the real Query editor in a foreign appAdds a
widgetsvite entry (toolbar pattern) exposingwindow.PostHogWidgets.mountQueryEditor(el, { query, onQueryChange, apiHost, getAccessToken, theme, onClose })→{ update, unmount }. Internally: shadow root with injected styles, own React 18 + kea copy,FloatingContainerContextpointing popovers/tooltips inside the shadow root, and the full editableQuery/InsightVizeditor (series, math, TaxonomicFilter, breakdown/filters) emitting plain query JSON to the host.lib/api.ts, plus one new seam:setOAuthSessionOverride(session, refreshFn)— an in-memory session (never persisted in the host origin) whose 401 path calls the host's token refresh.userLogic+teamLogicneed explicit mounting; the rest self-mounts via keaconnect.loadUserSuccessseedsApiConfigids in OAuth mode — noPOSTHOG_APP_CONTEXTrequired.onQueryChangeround-trips, live theme flip restyles open popovers. See companion PR for details and the harness.Bundle:
widgets.js2.03 MB (603 KB gz) + CSS 137 KB gz; ~2.7 MB gz eager mount cost; 186 lazy chunks deferred.If this graduates from experiment, the maintainability contract would be: keep the entry building, keep tokens on
:root, :host, keepFloatingContainerContexthonored by portaling primitives, promotesetOAuthSessionOverrideto a first-class embedded-auth API, and add a size budget likecheck-toolbar-size.Screenshots
🤖 Generated with Claude Code