Watch admin static_root and serve assets via dev server WebSocket#7152
Watch admin static_root and serve assets via dev server WebSocket#7152melissaluu wants to merge 6 commits intomainfrom
Conversation
|
We detected some changes at Caution DO NOT create changesets for features which you do not wish to be included in the public changelog of the next CLI release. |
There was a problem hiding this comment.
Pull request overview
Adds support to the UI extensions dev server for app-level “asset directories” (starting with admin extension static_root), including HTTP serving and WebSocket payload updates so clients can invalidate/reload assets when files change.
Changes:
- Extend dev server WebSocket payload/types with optional
app.assets(keyed map of{url, lastUpdated}). - Serve app-level assets from
/extensions/assets/:assetKey/**:filePathwhen configured. - Watch configured asset directories and broadcast
lastUpdatedtimestamp bumps on changes; re-resolve assets on app reload.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/ui-extensions-server-kit/src/types.ts | Adds App.assets to the shared server-kit type surface. |
| packages/app/src/cli/services/dev/processes/previewable-extension.ts | Resolves and passes appAssets into the dev server process options. |
| packages/app/src/cli/services/dev/extension/server/middlewares.ts | Introduces getAppAssetsMiddleware for serving app-level assets. |
| packages/app/src/cli/services/dev/extension/server/middlewares.test.ts | Adds middleware tests for serving app assets + unknown key 404. |
| packages/app/src/cli/services/dev/extension/server.ts | Wires the new assets route into the HTTP server when appAssets is present. |
| packages/app/src/cli/services/dev/extension/payload/store.ts | Adds appAssets to payload initialization and new store update APIs. |
| packages/app/src/cli/services/dev/extension/payload/store.test.ts | Adds unit tests for app asset timestamp updates + payload initialization behavior. |
| packages/app/src/cli/services/dev/extension/payload/models.ts | Adds app.assets to the server-side payload model interface. |
| packages/app/src/cli/services/dev/extension.ts | Implements resolveAppAssets, chokidar watchers, and app reload plumbing. |
| packages/app/src/cli/services/dev/extension.test.ts | Adds tests for resolveAppAssets and passing appAssets through to HTTP server setup. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
packages/app/src/cli/services/dev/extension/server/middlewares.ts
Outdated
Show resolved
Hide resolved
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… leak - Changed appAssets from a captured reference to a getAppAssets() callback in setupHTTPServer and getAppAssetsMiddleware, so the middleware always reads fresh asset config after app reloads - Replaced unbounded debounceTimers array with a Map<string, setTimeout> keyed by assetKey, so each key has at most one timer entry Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…and fix upload assets on change Co-authored-by: Trish Ta <trish.ta@shopify.com>
53e7bea to
5ce5d81
Compare
Summary
Adds end-to-end support for watching admin extension
static_rootdirectories duringshopify app dev. When files change in the configuredstatic_rootdirectory, the dev server detects the change, updates asset timestamps in the payload store, and broadcasts the update over WebSocket so connected clients can react.This PR does not include exposing CSP content for the app.
What changed
File watching pipeline — Extended the existing
FileWatcher→AppEventWatcher→ dev server pipeline with a newapp_asset_updatedevent type. TheFileWatcherresolvesstatic_rootfrom the admin extension config, watches that directory, and emitsapp_asset_updatedevents on file changes. A newAppAssetUpdatedHandlerpropagates these asAppEvents with anappAssetsUpdatedflag.dist/ignore exemption — Replaced the static**/dist/**chokidar ignore pattern with a function that allowsdist/paths through when they fall under a watched app asset directory (sincestatic_rootmay point to adist/folder).Payload store — Added
app.assetsto the WebSocket payload model: aRecord<string, { url, lastUpdated }>. New methodsupdateAppAssetTimestamp()andupdateAppAssets()manage timestamps and emit updates to WebSocket clients.HTTP serving — Added a parameterized route at
/extensions/assets/:assetKey/:filePaththat serves files from the resolved asset directory.Admin spec — Set
experience: 'configuration'so the admin extension loads fromshopify.app.toml. Added a proper zod schema ({ admin: { static_root? } }) so the extension is only instantiated when[admin]is present in the config. Also added optionalschemasupport tocreateContractBasedModuleSpecificationto enable this.Test plan
loader.test.ts— 129 tests pass, including the 3 that were failing due to the admin spec changeextension.test.ts—resolveAppAssets()returns correct map;appAssetspassed through to HTTP server;getAppAssetscallback worksstore.test.ts—updateAppAssetTimestampupdates timestamp and emits;updateAppAssetsrebuilds or removes assets; raw payload populatesapp.assetswhen configuredmiddlewares.test.ts—getAppAssetsMiddlewareserves files for valid keys, returns 404 for unknown keysfile-watcher.test.ts— Updated chokidar ignored pattern assertion for the newdist/filter functionapp-event-watcher.test.ts— 19 tests pass🤖 Generated with Claude Code