Skip to content

feat(workbench): build app view artifacts and register them on deploy#1149

Draft
gu-stav wants to merge 11 commits into
feat/cli-dock-group-priorityfrom
feat/cli-dock-panels
Draft

feat(workbench): build app view artifacts and register them on deploy#1149
gu-stav wants to merge 11 commits into
feat/cli-dock-group-priorityfrom
feat/cli-dock-panels

Conversation

@gu-stav
Copy link
Copy Markdown
Member

@gu-stav gu-stav commented Jun 2, 2026

CLI side of workbench US3 (panel views). Stacked on #1146.

Threads the app's declared views from sanity.cli.ts through build and dev into the @sanity/federation/vite plugin, so each view's src is built into a render artifact (exposed via module federation as ./views/<name>).

On sanity deploy, the views are validated into the application-service payload and logged — the service that stores them doesn't exist yet, so nothing is sent, but a malformed view declaration fails the deploy before the bundle ships. Adds app.views to the CLI config type.

Depends on the unstable_defineView / views surface in @sanity/federation (sanity-io/workbench#236); consumed via a pkg.pr.new preview once it lands.

gu-stav and others added 2 commits June 2, 2026 10:47
Threads the app's declared views from sanity.cli.ts through to the
federation vite plugin (build + dev), so each view's src is built into a
render artifact under .sanity/federation/views. On deploy, the views are
validated into the application-service payload and logged — the service
that stores them doesn't exist yet, so nothing is sent, but a malformed
view declaration fails the deploy before the bundle ships.
@claude
Copy link
Copy Markdown

claude Bot commented Jun 2, 2026

Claude finished @gu-stav's task in 2m 52s —— View job


Review

  • Read PR diff against origin/feat/cli-dock-group-priority
  • Inspect new/modified files
  • Verify changeset
  • Post findings

Blockers before merge

1. pkg.pr.new dependency cannot be released. package.json and pnpm-lock.yaml pin @sanity/federation to https://pkg.pr.new/sanity-io/workbench/@sanity/federation@1a9ececc…. A published @sanity/cli with a pkg.pr.new URL in its dep graph will break every consumer install (pkg.pr.new tarballs are ephemeral, and the overrides field doesn't propagate to consumers anyway). Must be swapped for a real npm version of @sanity/federation before merge. PR description acknowledges this — flagging so it doesn't slip through.

2. No tests for viewDeployment.ts or the new deploy branch. viewDeployment.ts is brand-new and has 66.7% statement coverage; deployApp.ts regressed 7.4%. The validation gates the deploy ({exit: 1}), so the regex / enum / passthrough behavior needs unit coverage at minimum:

  • accepts a valid panel view
  • rejects an invalid name
  • rejects an unknown type
  • passthrough keeps extra attrs
  • empty input is a no-op (payload.views = [])

Issues

3. Zod error surfaced to user is unreadable. packages/@sanity/cli/src/actions/deploy/deployApp.ts:160-161 does getErrorMessage(err) on a ZodError. err.message on a ZodError is the stringified issue array — a wall of JSON. Use z.prettifyError(err) (zod v4) or format the issues manually so users see something like "View name must match …" instead of [{ "code": "invalid_string", "validation": "regex", … }].

4. Production deploy output dumps full JSON payload. deployApp.ts:154-158 calls output.log(JSON.stringify(payload, null, 2)) on every deploy that declares views. Even with one or two views this is noisy mid-deploy; with many it floods the terminal. Since deployDebug('View deployment payload', payload) is called immediately after, the user-facing output.log of the JSON should be dropped — keep the one-line "Validated N view(s) …" message and let DEBUG=sanity:* reveal the payload.

5. Lenient/strict schema split can pass dev and fail deploy. devServerRegistry.ts:42-48 accepts type: z.string(); viewDeployment.ts:11 enforces type: z.enum(['panel']). A typo (type: 'pannel') builds and dev-runs cleanly, then blows up at deploy time with a Zod error. Either share the schema between dev/deploy, or emit a warning at dev-server registration when type isn't a known value, so the failure mode is consistent.

6. Regex error message echoes the pattern. viewDeployment.ts:9'View name must match /^[a-zA-Z0-9_-]+$/' is fine for engineers but not for end users seeing it during deploy. Per the project's product-copy guidance, prefer a human-readable rule: 'View name may only contain letters, numbers, dashes, and underscores'.

7. Changeset summary doesn't match repo product-copy conventions. .changeset/pr-1149.md reads feat(workbench): build app view artifacts and register them on deploy. Two problems:

  • It's a conventional-commit subject, not a one-sentence user-facing summary (compare .changeset/pr-1143.md: Add unstable_defineApp, exported from sanity/cli, …).
  • "register them on deploy" is misleading — the PR description explicitly says the service doesn't exist and nothing is sent. Recommend something closer to: Build view artifacts for workbench apps and validate view declarations during deploy.

Nits (non-blocking)

  • deployApp.ts:162return after output.error(…, {exit: 1}) is dead (the call exits the process), but it matches the surrounding pattern, so leave it.
  • viewDeployment.tsapplicationId is required by the schema and unused except in the logged payload. Fine as a Phase 1 contract stub; worth a TODO if you want to mark it.
    · Branch

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 2, 2026

📦 Bundle Stats — @sanity/cli

Compared against feat/cli-dock-group-priority (4265702c)

@sanity/cli

Metric Value vs feat/cli-dock-group-priority (4265702)
Internal (raw) 2.6 KB +214 B, +8.7%
Internal (gzip) 1.0 KB +115 B, +12.5%
Bundled (raw) 11.10 MB -
Bundled (gzip) 2.09 MB -
Import time 852ms +3ms, +0.3%

bin:sanity

Metric Value vs feat/cli-dock-group-priority (4265702)
Internal (raw) 1023 B -
Internal (gzip) 486 B -
Bundled (raw) 9.84 MB -
Bundled (gzip) 1.77 MB -
Import time 2.00s +2ms, +0.1%

🗺️ View treemap · Artifacts

Details
  • Import time regressions over 10% are flagged with ⚠️
  • Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.

📦 Bundle Stats — @sanity/cli-core

Compared against feat/cli-dock-group-priority (4265702c)

Metric Value vs feat/cli-dock-group-priority (4265702)
Internal (raw) 102.3 KB -
Internal (gzip) 24.7 KB -
Bundled (raw) 21.77 MB -
Bundled (gzip) 3.45 MB -
Import time 800ms -0ms, -0.1%

🗺️ View treemap · Artifacts

Details
  • Import time regressions over 10% are flagged with ⚠️
  • Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.

📦 Bundle Stats — create-sanity

Compared against feat/cli-dock-group-priority (4265702c)

Metric Value vs feat/cli-dock-group-priority (4265702)
Internal (raw) 908 B -
Internal (gzip) 483 B -
Bundled (raw) 931 B -
Bundled (gzip) 491 B -
Import time ❌ ChildProcess denied: node -
Details
  • Import time regressions over 10% are flagged with ⚠️
  • Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.

@gu-stav gu-stav changed the title feat(cli): build app view artifacts and register them on deploy feat(workbench): build app view artifacts and register them on deploy Jun 2, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 2, 2026

Coverage Delta

File Statements
packages/@sanity/cli-core/src/config/cli/getCliConfig.ts 100.0% (±0%)
packages/@sanity/cli-core/src/config/cli/getCliConfigSync.ts 81.0% (+ 38.9%)
packages/@sanity/cli-core/src/config/cli/workbenchApp.ts 100.0% (new)
packages/@sanity/cli-core/src/services/cliUserConfig.ts 100.0% (±0%)
packages/@sanity/cli-core/src/util/getSanityConfigDir.ts 66.7% (new)
packages/@sanity/cli/src/actions/build/buildApp.ts 95.4% (+ 0.1%)
packages/@sanity/cli/src/actions/build/buildStaticFiles.ts 97.6% (+ 0.9%)
packages/@sanity/cli/src/actions/build/buildStudio.ts 96.7% (+ 0.1%)
packages/@sanity/cli/src/actions/build/getViteConfig.ts 100.0% (new)
packages/@sanity/cli/src/actions/build/writeSanityRuntime.ts 96.2% (new)
packages/@sanity/cli/src/actions/deploy/deployApp.ts 73.2% (- 7.4%)
packages/@sanity/cli/src/actions/deploy/deployStudioSchemasAndManifests.ts 100.0% (±0%)
packages/@sanity/cli/src/actions/deploy/viewDeployment.ts 66.7% (new)
packages/@sanity/cli/src/actions/dev/devAction.ts 96.7% (- 3.3%)
packages/@sanity/cli/src/actions/dev/devServerRegistry.ts 93.8% (new)
packages/@sanity/cli/src/actions/dev/extractDevServerManifest.ts 20.0% (new)
packages/@sanity/cli/src/actions/dev/getDevServerConfig.ts 100.0% (±0%)
packages/@sanity/cli/src/actions/dev/startAppDevServer.ts 100.0% (+ 13.0%)
packages/@sanity/cli/src/actions/dev/startDevManifestWatcher.ts 90.9% (new)
packages/@sanity/cli/src/actions/dev/startFederationRegistration.ts 93.3% (new)
packages/@sanity/cli/src/actions/dev/startStudioDevServer.ts 100.0% (+ 5.0%)
packages/@sanity/cli/src/actions/dev/startWorkbenchDevServer.ts 98.7% (new)
packages/@sanity/cli/src/actions/dev/writeWorkbenchRuntime.ts 100.0% (new)
packages/@sanity/cli/src/actions/init/createAppCliConfig.ts 100.0% (±0%)
packages/@sanity/cli/src/actions/init/createCliConfig.ts 50.0% (±0%)
packages/@sanity/cli/src/actions/manifest/extractCoreAppManifest.ts 93.1% (new)
packages/@sanity/cli/src/actions/manifest/extractManifest.ts 100.0% (±0%)
packages/@sanity/cli/src/actions/manifest/types.ts 100.0% (±0%)
packages/@sanity/cli/src/actions/manifest/writeManifestFile.ts 100.0% (±0%)
packages/@sanity/cli/src/commands/dev.ts 100.0% (±0%)
packages/@sanity/cli/src/commands/manifest/extract.ts 100.0% (±0%)
packages/@sanity/cli/src/commands/schemas/deploy.ts 95.0% (±0%)
packages/@sanity/cli/src/server/devServer.ts 94.1% (- 0.3%)
packages/@sanity/cli/src/util/determineIsApp.ts 100.0% (±0%)
packages/@sanity/cli/src/util/getSharedServerConfig.ts 100.0% (±0%)
packages/@sanity/cli/src/util/resolveReactStrictMode.ts 100.0% (new)

Comparing 36 changed files against main @ e051d475cae2e183706300793b1d797a7b876a1f

Overall Coverage

Metric Coverage
Statements 84.7% (+ 0.3%)
Branches 74.7% (+ 0.1%)
Functions 84.4% (+ 0.1%)
Lines 85.2% (+ 0.3%)

gu-stav and others added 4 commits June 2, 2026 11:09
`views` is an `unstable_defineApp` field — its source of truth is
`DefineAppInput` in @sanity/federation, not the legacy `app` config
object on CliConfig. Drop it from the cli-core type and read it through
the `isWorkbenchApp` narrowing at each call site (build, dev, deploy),
so the field lives in one place.
Studio dev already threaded views (shared getDevServerConfig), but studio
build dropped them — so a studio opting into unstable_defineApp with views
emitted no artifacts. Read views off the branded app and thread them
through buildStudio for parity with apps. Views apply to coreApp and
studio alike, per each one's cli config.
So local panels render without a deploy: carry the branded app's views on
the dev-server registry entry (alongside the manifest, not inside it — views
live in the application service) and include them in the local-applications
payload the workbench subscribes to.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 2, 2026

Preview this PR with pkg.pr.new

Run the Sanity CLI

npx https://pkg.pr.new/sanity-io/cli/@sanity/cli@b545773 <command>

...Or upgrade project dependencies

📦 @sanity/cli
pnpm install https://pkg.pr.new/@sanity/cli@b545773
📦 @sanity/cli-build
pnpm install https://pkg.pr.new/@sanity/cli-build@b545773
📦 @sanity/cli-core
pnpm install https://pkg.pr.new/@sanity/cli-core@b545773
📦 @sanity/cli-test
pnpm install https://pkg.pr.new/@sanity/cli-test@b545773
📦 @sanity/eslint-config-cli
pnpm install https://pkg.pr.new/@sanity/eslint-config-cli@b545773

View Commit (b545773)

gu-stav added 4 commits June 2, 2026 12:33
Pin @sanity/federation to the sanity-io/workbench#236 pkg.pr.new preview
so the views/ViewArtifact surface resolves at typecheck time, and
un-export viewDeploymentPayloadSchema / ViewDeploymentPayload (used only
internally) so knip's depcheck passes.
So view src files can import it alongside unstable_defineApp until the
sanity runtime package surfaces it. Canonical impl stays in
@sanity/federation; no prop types re-exported (inferred at the call site).
Importing unstable_defineView from the main @sanity/cli entry dragged
cli-core's Node worker loader into the browser federation bundle and broke
view builds. Move the runtime helper to a dedicated @sanity/cli/runtime
entry that re-exports only from @sanity/federation — no cli-core/Node
imports — so view src files (and the future sanity runtime re-export) stay
out of the CLI's dependency graph. defineApp stays config-time on the main
entry.
The workbench renamed the application-surface concept from views to
interfaces (one per interface_type, the shape the application service
returns). Map each declared view to that local interface shape on the
dev-server registry entry — { interface_type, name, entry_point }, with
the local dev server as the entry_point — so the workbench parses and
renders local panels. Non-local (deployed) entry_points are deferred.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant