Skip to content

Watch admin static_root and serve assets via dev server WebSocket#7152

Open
melissaluu wants to merge 6 commits intomainfrom
ml-add-staticRoot-ext-websocket
Open

Watch admin static_root and serve assets via dev server WebSocket#7152
melissaluu wants to merge 6 commits intomainfrom
ml-add-staticRoot-ext-websocket

Conversation

@melissaluu
Copy link
Copy Markdown

@melissaluu melissaluu commented Apr 1, 2026

Summary

Adds end-to-end support for watching admin extension static_root directories during shopify app dev. When files change in the configured static_root directory, 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 FileWatcherAppEventWatcher → dev server pipeline with a new app_asset_updated event type. The FileWatcher resolves static_root from the admin extension config, watches that directory, and emits app_asset_updated events on file changes. A new AppAssetUpdatedHandler propagates these as AppEvents with an appAssetsUpdated flag.

dist/ ignore exemption — Replaced the static **/dist/** chokidar ignore pattern with a function that allows dist/ paths through when they fall under a watched app asset directory (since static_root may point to a dist/ folder).

Payload store — Added app.assets to the WebSocket payload model: a Record<string, { url, lastUpdated }>. New methods updateAppAssetTimestamp() and updateAppAssets() manage timestamps and emit updates to WebSocket clients.

HTTP serving — Added a parameterized route at /extensions/assets/:assetKey/:filePath that serves files from the resolved asset directory.

Admin spec — Set experience: 'configuration' so the admin extension loads from shopify.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 optional schema support to createContractBasedModuleSpecification to enable this.

Test plan

  • loader.test.ts — 129 tests pass, including the 3 that were failing due to the admin spec change
  • extension.test.tsresolveAppAssets() returns correct map; appAssets passed through to HTTP server; getAppAssets callback works
  • store.test.tsupdateAppAssetTimestamp updates timestamp and emits; updateAppAssets rebuilds or removes assets; raw payload populates app.assets when configured
  • middlewares.test.tsgetAppAssetsMiddleware serves files for valid keys, returns 404 for unknown keys
  • file-watcher.test.ts — Updated chokidar ignored pattern assertion for the new dist/ filter function
  • app-event-watcher.test.ts — 19 tests pass

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings April 1, 2026 23:02
@melissaluu melissaluu requested a review from a team as a code owner April 1, 2026 23:02
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 1, 2026

We detected some changes at packages/*/src and there are no updates in the .changeset.
If the changes are user-facing, run pnpm changeset add to track your changes and include them in the next release CHANGELOG.

Caution

DO NOT create changesets for features which you do not wish to be included in the public changelog of the next CLI release.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

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/**:filePath when configured.
  • Watch configured asset directories and broadcast lastUpdated timestamp 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.

melissaluu and others added 5 commits April 2, 2026 14:55
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>
@melissaluu melissaluu force-pushed the ml-add-staticRoot-ext-websocket branch from 53e7bea to 5ce5d81 Compare April 2, 2026 18:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants