@sanity/cli 7.4.0 → 7.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -1
- package/dist/actions/build/buildApp.js +20 -17
- package/dist/actions/build/buildApp.js.map +1 -1
- package/dist/actions/build/buildStudio.js +23 -21
- package/dist/actions/build/buildStudio.js.map +1 -1
- package/dist/actions/dev/devAction.js +46 -197
- package/dist/actions/dev/devAction.js.map +1 -1
- package/dist/actions/dev/servers/getDevServerConfig.js +1 -1
- package/dist/actions/dev/servers/getDevServerConfig.js.map +1 -1
- package/dist/actions/dev/servers/startAppDevServer.js +18 -9
- package/dist/actions/dev/servers/startAppDevServer.js.map +1 -1
- package/dist/actions/dev/servers/startStudioDevServer.js +2 -2
- package/dist/actions/dev/servers/startStudioDevServer.js.map +1 -1
- package/dist/actions/dev/types.js.map +1 -1
- package/dist/actions/{dev/registration/extractDevServerManifest.js → manifest/extractStudioManifest.js} +3 -3
- package/dist/actions/manifest/extractStudioManifest.js.map +1 -0
- package/dist/actions/mcp/editorConfigs.js +8 -4
- package/dist/actions/mcp/editorConfigs.js.map +1 -1
- package/dist/commands/datasets/copy.js +17 -19
- package/dist/commands/datasets/copy.js.map +1 -1
- package/dist/commands/datasets/import.js +11 -15
- package/dist/commands/datasets/import.js.map +1 -1
- package/dist/commands/doctor.js +9 -9
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/telemetry/disable.js +3 -3
- package/dist/commands/telemetry/disable.js.map +1 -1
- package/dist/commands/telemetry/enable.js +3 -3
- package/dist/commands/telemetry/enable.js.map +1 -1
- package/dist/commands/telemetry/status.js +2 -2
- package/dist/commands/telemetry/status.js.map +1 -1
- package/dist/exports/_internal.d.ts +4 -47
- package/dist/exports/_internal.js +1 -1
- package/dist/exports/_internal.js.map +1 -1
- package/dist/server/devServer.js +1 -1
- package/dist/server/devServer.js.map +1 -1
- package/dist/util/compareDependencyVersions.js.map +1 -1
- package/oclif.manifest.json +1 -1
- package/package.json +9 -8
- package/dist/actions/build/buildStaticFiles.js +0 -144
- package/dist/actions/build/buildStaticFiles.js.map +0 -1
- package/dist/actions/build/getEnvironmentVariables.js +0 -54
- package/dist/actions/build/getEnvironmentVariables.js.map +0 -1
- package/dist/actions/dev/registration/deriveInterfaces.js +0 -46
- package/dist/actions/dev/registration/deriveInterfaces.js.map +0 -1
- package/dist/actions/dev/registration/extractDevServerManifest.js.map +0 -1
- package/dist/actions/dev/registration/interfaceSetId.js +0 -41
- package/dist/actions/dev/registration/interfaceSetId.js.map +0 -1
- package/dist/actions/dev/registration/startDevManifestWatcher.js +0 -104
- package/dist/actions/dev/registration/startDevManifestWatcher.js.map +0 -1
- package/dist/actions/dev/registration/startDevServerRegistration.js +0 -121
- package/dist/actions/dev/registration/startDevServerRegistration.js.map +0 -1
- package/dist/actions/dev/workbench/startWorkbenchDevServer.js +0 -276
- package/dist/actions/dev/workbench/startWorkbenchDevServer.js.map +0 -1
- package/dist/actions/dev/workbench/writeWorkbenchRuntime.js +0 -66
- package/dist/actions/dev/workbench/writeWorkbenchRuntime.js.map +0 -1
- package/dist/util/formatSize.js +0 -10
- package/dist/util/formatSize.js.map +0 -1
- package/dist/util/moduleFormatUtils.js +0 -18
- package/dist/util/moduleFormatUtils.js.map +0 -1
|
@@ -1,276 +0,0 @@
|
|
|
1
|
-
import { SANITY_CACHE_DIR } from '@sanity/cli-build/_internal/build';
|
|
2
|
-
import { isWorkbenchApp, resolveLocalPackage } from '@sanity/cli-core';
|
|
3
|
-
import { acquireWorkbenchLock, getRegisteredServers, readWorkbenchLock, watchRegistry } from '@sanity/workbench-cli/dev';
|
|
4
|
-
import viteReact from '@vitejs/plugin-react';
|
|
5
|
-
import { createServer } from 'vite';
|
|
6
|
-
import { z } from 'zod/mini';
|
|
7
|
-
import { resolveReactStrictMode } from '../../../util/resolveReactStrictMode.js';
|
|
8
|
-
import { devDebug } from '../devDebug.js';
|
|
9
|
-
import { interfaceSetId } from '../registration/interfaceSetId.js';
|
|
10
|
-
import { writeWorkbenchRuntime } from './writeWorkbenchRuntime.js';
|
|
11
|
-
const noop = async ()=>{};
|
|
12
|
-
/** Stable per-app key for the registry-watch interface diff. */ const serverKey = (s)=>`${s.id ?? ''}@${s.host ?? ''}:${s.port}`;
|
|
13
|
-
const toApplicationsPayload = (servers)=>({
|
|
14
|
-
applications: servers.map(({ host, id, interfaces, manifest, port, projectId, type })=>({
|
|
15
|
-
host,
|
|
16
|
-
id,
|
|
17
|
-
interfaces,
|
|
18
|
-
manifest,
|
|
19
|
-
port,
|
|
20
|
-
projectId,
|
|
21
|
-
type
|
|
22
|
-
}))
|
|
23
|
-
});
|
|
24
|
-
/**
|
|
25
|
-
* Start the workbench dev server when federation is enabled and the workbench
|
|
26
|
-
* package is available. If the desired port is already taken — by another
|
|
27
|
-
* workbench instance or an unrelated process — fall back to running without a
|
|
28
|
-
* workbench and let the app/studio dev server claim the configured port.
|
|
29
|
-
*/ export async function startWorkbenchDevServer(options) {
|
|
30
|
-
const { cliConfig, httpHost, httpPort: workbenchPort, output, workDir } = options;
|
|
31
|
-
// Workbench is opted into solely by calling `unstable_defineApp`.
|
|
32
|
-
if (!isWorkbenchApp(cliConfig?.app)) {
|
|
33
|
-
devDebug('Not a workbench app, skipping workbench dev server');
|
|
34
|
-
return {
|
|
35
|
-
close: noop,
|
|
36
|
-
httpHost,
|
|
37
|
-
workbenchAvailable: false,
|
|
38
|
-
workbenchPort
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
let workbenchAvailable = false;
|
|
42
|
-
try {
|
|
43
|
-
await resolveLocalPackage('sanity/workbench', workDir);
|
|
44
|
-
workbenchAvailable = true;
|
|
45
|
-
} catch {
|
|
46
|
-
devDebug('Workbench not available, skipping workbench dev server');
|
|
47
|
-
}
|
|
48
|
-
if (!workbenchAvailable) {
|
|
49
|
-
return {
|
|
50
|
-
close: noop,
|
|
51
|
-
httpHost,
|
|
52
|
-
workbenchAvailable,
|
|
53
|
-
workbenchPort
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
// Acquire an exclusive lock — only one workbench per machine.
|
|
57
|
-
// Uses O_EXCL which is atomic at the OS level, preventing races when
|
|
58
|
-
// multiple `sanity dev` processes start simultaneously (e.g. via turbo).
|
|
59
|
-
const workbenchLock = acquireWorkbenchLock({
|
|
60
|
-
host: httpHost || 'localhost',
|
|
61
|
-
port: workbenchPort
|
|
62
|
-
});
|
|
63
|
-
if (!workbenchLock) {
|
|
64
|
-
const existing = readWorkbenchLock();
|
|
65
|
-
devDebug('Workbench already running at pid %d on port %d, skipping', existing?.pid, existing?.port);
|
|
66
|
-
return {
|
|
67
|
-
close: noop,
|
|
68
|
-
httpHost: existing?.host ?? httpHost,
|
|
69
|
-
workbenchAvailable: true,
|
|
70
|
-
workbenchPort: existing?.port ?? workbenchPort
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
// The lock is already held; an exception here (runtime-file write failure,
|
|
74
|
-
// invalid remote URL) would otherwise leak it until the next acquire prunes
|
|
75
|
-
// the stale PID.
|
|
76
|
-
let result;
|
|
77
|
-
try {
|
|
78
|
-
result = await createWorkbenchViteServer({
|
|
79
|
-
cliConfig,
|
|
80
|
-
httpHost,
|
|
81
|
-
output,
|
|
82
|
-
workbenchPort,
|
|
83
|
-
workDir
|
|
84
|
-
});
|
|
85
|
-
} catch (err) {
|
|
86
|
-
workbenchLock.release();
|
|
87
|
-
throw err;
|
|
88
|
-
}
|
|
89
|
-
if (!result) {
|
|
90
|
-
workbenchLock.release();
|
|
91
|
-
return {
|
|
92
|
-
close: noop,
|
|
93
|
-
httpHost,
|
|
94
|
-
workbenchAvailable: false,
|
|
95
|
-
workbenchPort
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
const { actualPort, close } = result;
|
|
99
|
-
workbenchLock.updatePort(actualPort);
|
|
100
|
-
return {
|
|
101
|
-
close: async ()=>{
|
|
102
|
-
workbenchLock.release();
|
|
103
|
-
await close();
|
|
104
|
-
},
|
|
105
|
-
httpHost,
|
|
106
|
-
workbenchAvailable,
|
|
107
|
-
workbenchPort: actualPort
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
async function createWorkbenchViteServer(options) {
|
|
111
|
-
const { cliConfig, httpHost, output, workbenchPort, workDir } = options;
|
|
112
|
-
const remoteUrl = parseRemoteUrl(process.env.SANITY_INTERNAL_WORKBENCH_REMOTE_URL);
|
|
113
|
-
// The workbench runtime template needs a concrete boolean (it has no studio
|
|
114
|
-
// default to defer to), so collapse an unset config to off.
|
|
115
|
-
const reactStrictMode = resolveReactStrictMode(cliConfig) ?? false;
|
|
116
|
-
const organizationId = resolveOrganizationId(cliConfig);
|
|
117
|
-
devDebug('Writing workbench runtime files');
|
|
118
|
-
const root = await writeWorkbenchRuntime({
|
|
119
|
-
cwd: workDir,
|
|
120
|
-
organizationId,
|
|
121
|
-
reactStrictMode,
|
|
122
|
-
remoteUrl
|
|
123
|
-
});
|
|
124
|
-
const viteConfig = {
|
|
125
|
-
// Custom cache directory so sanity's vite cache doesn't conflict with local vite projects
|
|
126
|
-
cacheDir: `${SANITY_CACHE_DIR}/vite`,
|
|
127
|
-
configFile: false,
|
|
128
|
-
define: {
|
|
129
|
-
__SANITY_STAGING__: process.env.SANITY_INTERNAL_ENV === 'staging',
|
|
130
|
-
'import.meta.env.SANITY_INTERNAL_WORKBENCH_REMOTE_URL': JSON.stringify(remoteUrl)
|
|
131
|
-
},
|
|
132
|
-
logLevel: 'warn',
|
|
133
|
-
mode: 'development',
|
|
134
|
-
optimizeDeps: {
|
|
135
|
-
// Exclude sanity/workbench (and its transitive dep @sanity/workbench)
|
|
136
|
-
// from dep pre-bundling so that `import.meta.hot` is available at
|
|
137
|
-
// runtime — pre-bundled modules do not receive Vite's HMR client
|
|
138
|
-
// injection, which causes the custom HMR events for local application
|
|
139
|
-
// discovery to silently not fire.
|
|
140
|
-
exclude: [
|
|
141
|
-
'sanity',
|
|
142
|
-
'@sanity/workbench'
|
|
143
|
-
]
|
|
144
|
-
},
|
|
145
|
-
// viteReact looks inert here — it transforms none of the host's own modules —
|
|
146
|
-
// but it's load-bearing for the remotes. It serves the Fast Refresh runtime at
|
|
147
|
-
// /@react-refresh and injects the preamble that defines window.$RefreshReg$. The
|
|
148
|
-
// federated remotes loaded into this page are react-refresh transformed, so
|
|
149
|
-
// without the preamble they throw "can't detect preamble", and without the
|
|
150
|
-
// runtime their /@react-refresh import (wired by @module-federation/vite's
|
|
151
|
-
// remoteHmr) fails. Dropping it as dead code broke every panel; see #1262.
|
|
152
|
-
plugins: [
|
|
153
|
-
viteReact(),
|
|
154
|
-
...remoteUrl ? [
|
|
155
|
-
remoteManifestPreloadHeaderPlugin(remoteUrl)
|
|
156
|
-
] : []
|
|
157
|
-
],
|
|
158
|
-
resolve: {
|
|
159
|
-
dedupe: [
|
|
160
|
-
'react',
|
|
161
|
-
'react-dom'
|
|
162
|
-
]
|
|
163
|
-
},
|
|
164
|
-
root,
|
|
165
|
-
server: {
|
|
166
|
-
host: httpHost,
|
|
167
|
-
port: workbenchPort,
|
|
168
|
-
strictPort: false,
|
|
169
|
-
warmup: {
|
|
170
|
-
clientFiles: [
|
|
171
|
-
'./workbench.js'
|
|
172
|
-
]
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
};
|
|
176
|
-
devDebug('Creating workbench vite server');
|
|
177
|
-
const server = await createServer(viteConfig);
|
|
178
|
-
try {
|
|
179
|
-
await server.listen();
|
|
180
|
-
} catch (err) {
|
|
181
|
-
await server.close();
|
|
182
|
-
output.warn(`Workbench dev server failed to start: ${err instanceof Error ? err.message : String(err)}`);
|
|
183
|
-
return undefined;
|
|
184
|
-
}
|
|
185
|
-
// Vite may have picked a different port if the desired one was occupied
|
|
186
|
-
const addr = server.httpServer?.address();
|
|
187
|
-
const actualPort = typeof addr === 'object' && addr ? addr.port : workbenchPort;
|
|
188
|
-
// Fire-and-forget: warm the workbench remote's Vite transform pipeline so
|
|
189
|
-
// the first browser request hits a pre-populated module graph.
|
|
190
|
-
if (remoteUrl) {
|
|
191
|
-
fetch(remoteUrl).then((r)=>r.body?.cancel()).catch(()=>{});
|
|
192
|
-
devDebug('Warming workbench remote at %s', remoteUrl);
|
|
193
|
-
}
|
|
194
|
-
server.ws.on('sanity:workbench:get-local-applications', (_, client)=>{
|
|
195
|
-
client.send('sanity:workbench:local-applications', toApplicationsPayload(getRegisteredServers()));
|
|
196
|
-
});
|
|
197
|
-
// A running app's declared interface set changing (a view/service added or
|
|
198
|
-
// removed in `sanity.cli.ts`) means its remote was rebuilt with new exposes.
|
|
199
|
-
// Module federation has the old remote-entry cached, so an in-place reconcile
|
|
200
|
-
// would load a stale remote (empty panel / no worker) — the page must reload
|
|
201
|
-
// to re-fetch it. A new/removed app, or a manifest-only edit (title/icon),
|
|
202
|
-
// reconciles softly as before. Source-file edits don't change the set, so they
|
|
203
|
-
// stay on the HMR path and never trip a reload here.
|
|
204
|
-
let knownInterfaces = new Map();
|
|
205
|
-
const registryWatcher = watchRegistry((servers)=>{
|
|
206
|
-
const rebuiltApp = servers.some((s)=>{
|
|
207
|
-
const key = serverKey(s);
|
|
208
|
-
return knownInterfaces.has(key) && knownInterfaces.get(key) !== interfaceSetId(s.interfaces);
|
|
209
|
-
});
|
|
210
|
-
knownInterfaces = new Map(servers.map((s)=>[
|
|
211
|
-
serverKey(s),
|
|
212
|
-
interfaceSetId(s.interfaces)
|
|
213
|
-
]));
|
|
214
|
-
if (rebuiltApp) {
|
|
215
|
-
server.ws.send({
|
|
216
|
-
type: 'full-reload'
|
|
217
|
-
});
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
220
|
-
server.ws.send('sanity:workbench:local-applications', toApplicationsPayload(servers));
|
|
221
|
-
});
|
|
222
|
-
return {
|
|
223
|
-
actualPort,
|
|
224
|
-
close: async ()=>{
|
|
225
|
-
registryWatcher.close();
|
|
226
|
-
await server.close();
|
|
227
|
-
}
|
|
228
|
-
};
|
|
229
|
-
}
|
|
230
|
-
// Workbench is opted into via `unstable_defineApp`, which carries the
|
|
231
|
-
// organization ID. Deliberately no fallback (e.g. resolving it from the
|
|
232
|
-
// configured project): the lookup would need an authenticated user and an
|
|
233
|
-
// API round-trip on every startup for something the opt-in already declares.
|
|
234
|
-
const resolveOrganizationId = (cliConfig)=>{
|
|
235
|
-
if (cliConfig.app?.organizationId) {
|
|
236
|
-
return cliConfig.app.organizationId;
|
|
237
|
-
}
|
|
238
|
-
throw new Error('Workbench requires an organization ID. Pass "organizationId" to unstable_defineApp() in sanity.cli.ts.');
|
|
239
|
-
};
|
|
240
|
-
// Restricts protocol to http(s) so the URL is safe to interpolate into HTML
|
|
241
|
-
// attributes and Link headers downstream.
|
|
242
|
-
const remoteUrlSchema = z.url({
|
|
243
|
-
normalize: true,
|
|
244
|
-
protocol: /^https?$/
|
|
245
|
-
});
|
|
246
|
-
function parseRemoteUrl(value) {
|
|
247
|
-
if (!value) return undefined;
|
|
248
|
-
const result = remoteUrlSchema.safeParse(value);
|
|
249
|
-
if (!result.success) {
|
|
250
|
-
throw new Error(`Invalid SANITY_INTERNAL_WORKBENCH_REMOTE_URL: ${value} (must be an http(s) URL)`);
|
|
251
|
-
}
|
|
252
|
-
return result.data;
|
|
253
|
-
}
|
|
254
|
-
/**
|
|
255
|
-
* Sets a `Link: <remoteUrl>; rel=preload; as=fetch; crossorigin` response header
|
|
256
|
-
* on the index document so the browser can start fetching the Module Federation
|
|
257
|
-
* manifest as soon as response headers arrive — before HTML parsing reaches the
|
|
258
|
-
* in-head preconnect hint. `as=fetch` matches how the federation runtime later
|
|
259
|
-
* retrieves the JSON manifest, allowing the preload entry to satisfy that fetch.
|
|
260
|
-
*/ function remoteManifestPreloadHeaderPlugin(remoteUrl) {
|
|
261
|
-
return {
|
|
262
|
-
apply: 'serve',
|
|
263
|
-
configureServer (server) {
|
|
264
|
-
server.middlewares.use((req, res, next)=>{
|
|
265
|
-
const pathname = (req.url || '/').split('?')[0];
|
|
266
|
-
if (pathname === '/' || pathname === '/index.html') {
|
|
267
|
-
res.setHeader('Link', `<${remoteUrl}>; rel=preload; as=fetch; crossorigin`);
|
|
268
|
-
}
|
|
269
|
-
next();
|
|
270
|
-
});
|
|
271
|
-
},
|
|
272
|
-
name: 'sanity:workbench-remote-preload-header'
|
|
273
|
-
};
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
//# sourceMappingURL=startWorkbenchDevServer.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/actions/dev/workbench/startWorkbenchDevServer.ts"],"sourcesContent":["import {SANITY_CACHE_DIR} from '@sanity/cli-build/_internal/build'\nimport {isWorkbenchApp, resolveLocalPackage} from '@sanity/cli-core'\nimport {\n acquireWorkbenchLock,\n type DevServerManifest,\n getRegisteredServers,\n readWorkbenchLock,\n watchRegistry,\n} from '@sanity/workbench-cli/dev'\nimport viteReact from '@vitejs/plugin-react'\nimport {createServer, type InlineConfig, type Plugin} from 'vite'\nimport {z} from 'zod/mini'\n\nimport {resolveReactStrictMode} from '../../../util/resolveReactStrictMode.js'\nimport {devDebug} from '../devDebug.js'\nimport {interfaceSetId} from '../registration/interfaceSetId.js'\nimport {type DevActionOptions} from '../types.js'\nimport {writeWorkbenchRuntime} from './writeWorkbenchRuntime.js'\n\nconst noop = async () => {}\n\n/** Stable per-app key for the registry-watch interface diff. */\nconst serverKey = (s: DevServerManifest) => `${s.id ?? ''}@${s.host ?? ''}:${s.port}`\n\nconst toApplicationsPayload = (servers: DevServerManifest[]) => ({\n applications: servers.map(({host, id, interfaces, manifest, port, projectId, type}) => ({\n host,\n id,\n interfaces,\n manifest,\n port,\n projectId,\n type,\n })),\n})\n\ninterface WorkbenchDevServerResult {\n close: () => Promise<void>\n httpHost: string | undefined\n workbenchAvailable: boolean\n workbenchPort: number\n}\n\nexport interface StartWorkbenchOptions extends DevActionOptions {\n httpHost: string | undefined\n httpPort: number\n}\n\n/**\n * Start the workbench dev server when federation is enabled and the workbench\n * package is available. If the desired port is already taken — by another\n * workbench instance or an unrelated process — fall back to running without a\n * workbench and let the app/studio dev server claim the configured port.\n */\nexport async function startWorkbenchDevServer(\n options: StartWorkbenchOptions,\n): Promise<WorkbenchDevServerResult> {\n const {cliConfig, httpHost, httpPort: workbenchPort, output, workDir} = options\n\n // Workbench is opted into solely by calling `unstable_defineApp`.\n if (!isWorkbenchApp(cliConfig?.app)) {\n devDebug('Not a workbench app, skipping workbench dev server')\n return {close: noop, httpHost, workbenchAvailable: false, workbenchPort}\n }\n\n let workbenchAvailable = false\n\n try {\n await resolveLocalPackage('sanity/workbench', workDir)\n workbenchAvailable = true\n } catch {\n devDebug('Workbench not available, skipping workbench dev server')\n }\n\n if (!workbenchAvailable) {\n return {close: noop, httpHost, workbenchAvailable, workbenchPort}\n }\n\n // Acquire an exclusive lock — only one workbench per machine.\n // Uses O_EXCL which is atomic at the OS level, preventing races when\n // multiple `sanity dev` processes start simultaneously (e.g. via turbo).\n const workbenchLock = acquireWorkbenchLock({host: httpHost || 'localhost', port: workbenchPort})\n if (!workbenchLock) {\n const existing = readWorkbenchLock()\n devDebug(\n 'Workbench already running at pid %d on port %d, skipping',\n existing?.pid,\n existing?.port,\n )\n return {\n close: noop,\n httpHost: existing?.host ?? httpHost,\n workbenchAvailable: true,\n workbenchPort: existing?.port ?? workbenchPort,\n }\n }\n\n // The lock is already held; an exception here (runtime-file write failure,\n // invalid remote URL) would otherwise leak it until the next acquire prunes\n // the stale PID.\n let result: Awaited<ReturnType<typeof createWorkbenchViteServer>>\n try {\n result = await createWorkbenchViteServer({\n cliConfig,\n httpHost,\n output,\n workbenchPort,\n workDir,\n })\n } catch (err) {\n workbenchLock.release()\n throw err\n }\n\n if (!result) {\n workbenchLock.release()\n return {close: noop, httpHost, workbenchAvailable: false, workbenchPort}\n }\n\n const {actualPort, close} = result\n workbenchLock.updatePort(actualPort)\n\n return {\n close: async () => {\n workbenchLock.release()\n await close()\n },\n httpHost,\n workbenchAvailable,\n workbenchPort: actualPort,\n }\n}\n\ninterface CreateWorkbenchViteServerOptions {\n cliConfig: DevActionOptions['cliConfig']\n httpHost: string | undefined\n output: DevActionOptions['output']\n workbenchPort: number\n workDir: string\n}\n\ninterface CreateWorkbenchViteServerResult {\n actualPort: number\n close: () => Promise<void>\n}\n\nasync function createWorkbenchViteServer(\n options: CreateWorkbenchViteServerOptions,\n): Promise<CreateWorkbenchViteServerResult | undefined> {\n const {cliConfig, httpHost, output, workbenchPort, workDir} = options\n\n const remoteUrl = parseRemoteUrl(process.env.SANITY_INTERNAL_WORKBENCH_REMOTE_URL)\n // The workbench runtime template needs a concrete boolean (it has no studio\n // default to defer to), so collapse an unset config to off.\n const reactStrictMode = resolveReactStrictMode(cliConfig) ?? false\n\n const organizationId = resolveOrganizationId(cliConfig)\n\n devDebug('Writing workbench runtime files')\n const root = await writeWorkbenchRuntime({\n cwd: workDir,\n organizationId,\n reactStrictMode,\n remoteUrl,\n })\n\n const viteConfig: InlineConfig = {\n // Custom cache directory so sanity's vite cache doesn't conflict with local vite projects\n cacheDir: `${SANITY_CACHE_DIR}/vite`,\n configFile: false,\n define: {\n __SANITY_STAGING__: process.env.SANITY_INTERNAL_ENV === 'staging',\n 'import.meta.env.SANITY_INTERNAL_WORKBENCH_REMOTE_URL': JSON.stringify(remoteUrl),\n },\n logLevel: 'warn',\n mode: 'development',\n optimizeDeps: {\n // Exclude sanity/workbench (and its transitive dep @sanity/workbench)\n // from dep pre-bundling so that `import.meta.hot` is available at\n // runtime — pre-bundled modules do not receive Vite's HMR client\n // injection, which causes the custom HMR events for local application\n // discovery to silently not fire.\n exclude: ['sanity', '@sanity/workbench'],\n },\n // viteReact looks inert here — it transforms none of the host's own modules —\n // but it's load-bearing for the remotes. It serves the Fast Refresh runtime at\n // /@react-refresh and injects the preamble that defines window.$RefreshReg$. The\n // federated remotes loaded into this page are react-refresh transformed, so\n // without the preamble they throw \"can't detect preamble\", and without the\n // runtime their /@react-refresh import (wired by @module-federation/vite's\n // remoteHmr) fails. Dropping it as dead code broke every panel; see #1262.\n plugins: [viteReact(), ...(remoteUrl ? [remoteManifestPreloadHeaderPlugin(remoteUrl)] : [])],\n resolve: {dedupe: ['react', 'react-dom']},\n root,\n server: {\n host: httpHost,\n port: workbenchPort,\n strictPort: false,\n warmup: {\n clientFiles: ['./workbench.js'],\n },\n },\n }\n\n devDebug('Creating workbench vite server')\n const server = await createServer(viteConfig)\n try {\n await server.listen()\n } catch (err) {\n await server.close()\n output.warn(\n `Workbench dev server failed to start: ${err instanceof Error ? err.message : String(err)}`,\n )\n return undefined\n }\n\n // Vite may have picked a different port if the desired one was occupied\n const addr = server.httpServer?.address()\n const actualPort = typeof addr === 'object' && addr ? addr.port : workbenchPort\n\n // Fire-and-forget: warm the workbench remote's Vite transform pipeline so\n // the first browser request hits a pre-populated module graph.\n if (remoteUrl) {\n fetch(remoteUrl)\n .then((r) => r.body?.cancel())\n .catch(() => {})\n devDebug('Warming workbench remote at %s', remoteUrl)\n }\n\n server.ws.on('sanity:workbench:get-local-applications', (_, client) => {\n client.send(\n 'sanity:workbench:local-applications',\n toApplicationsPayload(getRegisteredServers()),\n )\n })\n\n // A running app's declared interface set changing (a view/service added or\n // removed in `sanity.cli.ts`) means its remote was rebuilt with new exposes.\n // Module federation has the old remote-entry cached, so an in-place reconcile\n // would load a stale remote (empty panel / no worker) — the page must reload\n // to re-fetch it. A new/removed app, or a manifest-only edit (title/icon),\n // reconciles softly as before. Source-file edits don't change the set, so they\n // stay on the HMR path and never trip a reload here.\n let knownInterfaces = new Map<string, string>()\n const registryWatcher = watchRegistry((servers) => {\n const rebuiltApp = servers.some((s) => {\n const key = serverKey(s)\n return knownInterfaces.has(key) && knownInterfaces.get(key) !== interfaceSetId(s.interfaces)\n })\n knownInterfaces = new Map(servers.map((s) => [serverKey(s), interfaceSetId(s.interfaces)]))\n\n if (rebuiltApp) {\n server.ws.send({type: 'full-reload'})\n return\n }\n server.ws.send('sanity:workbench:local-applications', toApplicationsPayload(servers))\n })\n\n return {\n actualPort,\n close: async () => {\n registryWatcher.close()\n await server.close()\n },\n }\n}\n\n// Workbench is opted into via `unstable_defineApp`, which carries the\n// organization ID. Deliberately no fallback (e.g. resolving it from the\n// configured project): the lookup would need an authenticated user and an\n// API round-trip on every startup for something the opt-in already declares.\nconst resolveOrganizationId = (cliConfig: DevActionOptions['cliConfig']): string => {\n if (cliConfig.app?.organizationId) {\n return cliConfig.app.organizationId\n }\n\n throw new Error(\n 'Workbench requires an organization ID. Pass \"organizationId\" to unstable_defineApp() in sanity.cli.ts.',\n )\n}\n\n// Restricts protocol to http(s) so the URL is safe to interpolate into HTML\n// attributes and Link headers downstream.\nconst remoteUrlSchema = z.url({normalize: true, protocol: /^https?$/})\n\nfunction parseRemoteUrl(value: string | undefined): string | undefined {\n if (!value) return undefined\n\n const result = remoteUrlSchema.safeParse(value)\n\n if (!result.success) {\n throw new Error(\n `Invalid SANITY_INTERNAL_WORKBENCH_REMOTE_URL: ${value} (must be an http(s) URL)`,\n )\n }\n\n return result.data\n}\n\n/**\n * Sets a `Link: <remoteUrl>; rel=preload; as=fetch; crossorigin` response header\n * on the index document so the browser can start fetching the Module Federation\n * manifest as soon as response headers arrive — before HTML parsing reaches the\n * in-head preconnect hint. `as=fetch` matches how the federation runtime later\n * retrieves the JSON manifest, allowing the preload entry to satisfy that fetch.\n */\nfunction remoteManifestPreloadHeaderPlugin(remoteUrl: string): Plugin {\n return {\n apply: 'serve',\n configureServer(server) {\n server.middlewares.use((req, res, next) => {\n const pathname = (req.url || '/').split('?')[0]\n if (pathname === '/' || pathname === '/index.html') {\n res.setHeader('Link', `<${remoteUrl}>; rel=preload; as=fetch; crossorigin`)\n }\n next()\n })\n },\n name: 'sanity:workbench-remote-preload-header',\n }\n}\n"],"names":["SANITY_CACHE_DIR","isWorkbenchApp","resolveLocalPackage","acquireWorkbenchLock","getRegisteredServers","readWorkbenchLock","watchRegistry","viteReact","createServer","z","resolveReactStrictMode","devDebug","interfaceSetId","writeWorkbenchRuntime","noop","serverKey","s","id","host","port","toApplicationsPayload","servers","applications","map","interfaces","manifest","projectId","type","startWorkbenchDevServer","options","cliConfig","httpHost","httpPort","workbenchPort","output","workDir","app","close","workbenchAvailable","workbenchLock","existing","pid","result","createWorkbenchViteServer","err","release","actualPort","updatePort","remoteUrl","parseRemoteUrl","process","env","SANITY_INTERNAL_WORKBENCH_REMOTE_URL","reactStrictMode","organizationId","resolveOrganizationId","root","cwd","viteConfig","cacheDir","configFile","define","__SANITY_STAGING__","SANITY_INTERNAL_ENV","JSON","stringify","logLevel","mode","optimizeDeps","exclude","plugins","remoteManifestPreloadHeaderPlugin","resolve","dedupe","server","strictPort","warmup","clientFiles","listen","warn","Error","message","String","undefined","addr","httpServer","address","fetch","then","r","body","cancel","catch","ws","on","_","client","send","knownInterfaces","Map","registryWatcher","rebuiltApp","some","key","has","get","remoteUrlSchema","url","normalize","protocol","value","safeParse","success","data","apply","configureServer","middlewares","use","req","res","next","pathname","split","setHeader","name"],"mappings":"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"}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { devDebug } from '../devDebug.js';
|
|
4
|
-
const workbenchJsTemplate = `\
|
|
5
|
-
// This file is auto-generated on 'sanity dev'
|
|
6
|
-
// Modifications to this file are automatically discarded
|
|
7
|
-
import {renderWorkbench} from "sanity/workbench"
|
|
8
|
-
|
|
9
|
-
renderWorkbench(
|
|
10
|
-
document.getElementById("workbench"),
|
|
11
|
-
{organizationId: %SANITY_WORKBENCH_ORGANIZATION_ID%},
|
|
12
|
-
{reactStrictMode: %SANITY_WORKBENCH_REACT_STRICT_MODE%}
|
|
13
|
-
)
|
|
14
|
-
`;
|
|
15
|
-
const indexHtmlTemplate = `\
|
|
16
|
-
<!DOCTYPE html>
|
|
17
|
-
<!-- This file is auto-generated on 'sanity dev' -->
|
|
18
|
-
<!-- Modifications to this file are automatically discarded -->
|
|
19
|
-
<html>
|
|
20
|
-
<head>
|
|
21
|
-
<meta charset="UTF-8" />
|
|
22
|
-
%SANITY_WORKBENCH_PREFETCH_HINTS%
|
|
23
|
-
</head>
|
|
24
|
-
<body>
|
|
25
|
-
<div id="workbench"></div>
|
|
26
|
-
<script type="module" src="./workbench.js"></script>
|
|
27
|
-
</body>
|
|
28
|
-
</html>
|
|
29
|
-
`;
|
|
30
|
-
/**
|
|
31
|
-
* Generates the `.sanity/workbench` directory with static entry files for
|
|
32
|
-
* the workbench Vite dev server.
|
|
33
|
-
*
|
|
34
|
-
* @param cwd - Current working directory (Sanity root dir)
|
|
35
|
-
* @returns The absolute path to the written workbench runtime directory
|
|
36
|
-
* @internal
|
|
37
|
-
*/ export async function writeWorkbenchRuntime(options) {
|
|
38
|
-
const { cwd, organizationId, reactStrictMode, remoteUrl } = options;
|
|
39
|
-
const workbenchDir = path.join(cwd, '.sanity', 'workbench');
|
|
40
|
-
const workbenchJs = workbenchJsTemplate.replace(/%SANITY_WORKBENCH_ORGANIZATION_ID%/, organizationId === undefined ? 'undefined' : JSON.stringify(organizationId)).replace(/%SANITY_WORKBENCH_REACT_STRICT_MODE%/, JSON.stringify(reactStrictMode));
|
|
41
|
-
const prefetchHints = buildPrefetchHints(remoteUrl);
|
|
42
|
-
const indexHtml = indexHtmlTemplate.replace(/%SANITY_WORKBENCH_PREFETCH_HINTS%/, prefetchHints);
|
|
43
|
-
devDebug('Making workbench runtime directory');
|
|
44
|
-
await fs.mkdir(workbenchDir, {
|
|
45
|
-
recursive: true
|
|
46
|
-
});
|
|
47
|
-
devDebug('Writing workbench.js to workbench runtime directory');
|
|
48
|
-
await fs.writeFile(path.join(workbenchDir, 'workbench.js'), workbenchJs);
|
|
49
|
-
devDebug('Writing index.html to workbench runtime directory');
|
|
50
|
-
await fs.writeFile(path.join(workbenchDir, 'index.html'), indexHtml);
|
|
51
|
-
return workbenchDir;
|
|
52
|
-
}
|
|
53
|
-
function buildPrefetchHints(remoteUrl) {
|
|
54
|
-
if (!remoteUrl) return '';
|
|
55
|
-
try {
|
|
56
|
-
const url = new URL(remoteUrl);
|
|
57
|
-
return [
|
|
58
|
-
` <link rel="preconnect" href="${url.origin}" />`,
|
|
59
|
-
` <link rel="preload" as="fetch" href="${url.toString()}" crossorigin />`
|
|
60
|
-
].join('\n');
|
|
61
|
-
} catch {
|
|
62
|
-
return '';
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
//# sourceMappingURL=writeWorkbenchRuntime.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/actions/dev/workbench/writeWorkbenchRuntime.ts"],"sourcesContent":["import fs from 'node:fs/promises'\nimport path from 'node:path'\n\nimport {devDebug} from '../devDebug.js'\n\nconst workbenchJsTemplate = `\\\n// This file is auto-generated on 'sanity dev'\n// Modifications to this file are automatically discarded\nimport {renderWorkbench} from \"sanity/workbench\"\n\nrenderWorkbench(\n document.getElementById(\"workbench\"),\n {organizationId: %SANITY_WORKBENCH_ORGANIZATION_ID%},\n {reactStrictMode: %SANITY_WORKBENCH_REACT_STRICT_MODE%}\n)\n`\n\nconst indexHtmlTemplate = `\\\n<!DOCTYPE html>\n<!-- This file is auto-generated on 'sanity dev' -->\n<!-- Modifications to this file are automatically discarded -->\n<html>\n <head>\n <meta charset=\"UTF-8\" />\n%SANITY_WORKBENCH_PREFETCH_HINTS%\n </head>\n <body>\n <div id=\"workbench\"></div>\n <script type=\"module\" src=\"./workbench.js\"></script>\n </body>\n</html>\n`\n\n/**\n * Generates the `.sanity/workbench` directory with static entry files for\n * the workbench Vite dev server.\n *\n * @param cwd - Current working directory (Sanity root dir)\n * @returns The absolute path to the written workbench runtime directory\n * @internal\n */\nexport async function writeWorkbenchRuntime(options: {\n cwd: string\n organizationId?: string\n reactStrictMode: boolean\n remoteUrl?: string\n}): Promise<string> {\n const {cwd, organizationId, reactStrictMode, remoteUrl} = options\n const workbenchDir = path.join(cwd, '.sanity', 'workbench')\n\n const workbenchJs = workbenchJsTemplate\n .replace(\n /%SANITY_WORKBENCH_ORGANIZATION_ID%/,\n organizationId === undefined ? 'undefined' : JSON.stringify(organizationId),\n )\n .replace(/%SANITY_WORKBENCH_REACT_STRICT_MODE%/, JSON.stringify(reactStrictMode))\n\n const prefetchHints = buildPrefetchHints(remoteUrl)\n\n const indexHtml = indexHtmlTemplate.replace(/%SANITY_WORKBENCH_PREFETCH_HINTS%/, prefetchHints)\n\n devDebug('Making workbench runtime directory')\n await fs.mkdir(workbenchDir, {recursive: true})\n\n devDebug('Writing workbench.js to workbench runtime directory')\n await fs.writeFile(path.join(workbenchDir, 'workbench.js'), workbenchJs)\n\n devDebug('Writing index.html to workbench runtime directory')\n await fs.writeFile(path.join(workbenchDir, 'index.html'), indexHtml)\n\n return workbenchDir\n}\n\nfunction buildPrefetchHints(remoteUrl: string | undefined): string {\n if (!remoteUrl) return ''\n\n try {\n const url = new URL(remoteUrl)\n return [\n ` <link rel=\"preconnect\" href=\"${url.origin}\" />`,\n ` <link rel=\"preload\" as=\"fetch\" href=\"${url.toString()}\" crossorigin />`,\n ].join('\\n')\n } catch {\n return ''\n }\n}\n"],"names":["fs","path","devDebug","workbenchJsTemplate","indexHtmlTemplate","writeWorkbenchRuntime","options","cwd","organizationId","reactStrictMode","remoteUrl","workbenchDir","join","workbenchJs","replace","undefined","JSON","stringify","prefetchHints","buildPrefetchHints","indexHtml","mkdir","recursive","writeFile","url","URL","origin","toString"],"mappings":"AAAA,OAAOA,QAAQ,mBAAkB;AACjC,OAAOC,UAAU,YAAW;AAE5B,SAAQC,QAAQ,QAAO,iBAAgB;AAEvC,MAAMC,sBAAsB,CAAC;;;;;;;;;;AAU7B,CAAC;AAED,MAAMC,oBAAoB,CAAC;;;;;;;;;;;;;;AAc3B,CAAC;AAED;;;;;;;CAOC,GACD,OAAO,eAAeC,sBAAsBC,OAK3C;IACC,MAAM,EAACC,GAAG,EAAEC,cAAc,EAAEC,eAAe,EAAEC,SAAS,EAAC,GAAGJ;IAC1D,MAAMK,eAAeV,KAAKW,IAAI,CAACL,KAAK,WAAW;IAE/C,MAAMM,cAAcV,oBACjBW,OAAO,CACN,sCACAN,mBAAmBO,YAAY,cAAcC,KAAKC,SAAS,CAACT,iBAE7DM,OAAO,CAAC,wCAAwCE,KAAKC,SAAS,CAACR;IAElE,MAAMS,gBAAgBC,mBAAmBT;IAEzC,MAAMU,YAAYhB,kBAAkBU,OAAO,CAAC,qCAAqCI;IAEjFhB,SAAS;IACT,MAAMF,GAAGqB,KAAK,CAACV,cAAc;QAACW,WAAW;IAAI;IAE7CpB,SAAS;IACT,MAAMF,GAAGuB,SAAS,CAACtB,KAAKW,IAAI,CAACD,cAAc,iBAAiBE;IAE5DX,SAAS;IACT,MAAMF,GAAGuB,SAAS,CAACtB,KAAKW,IAAI,CAACD,cAAc,eAAeS;IAE1D,OAAOT;AACT;AAEA,SAASQ,mBAAmBT,SAA6B;IACvD,IAAI,CAACA,WAAW,OAAO;IAEvB,IAAI;QACF,MAAMc,MAAM,IAAIC,IAAIf;QACpB,OAAO;YACL,CAAC,iCAAiC,EAAEc,IAAIE,MAAM,CAAC,IAAI,CAAC;YACpD,CAAC,yCAAyC,EAAEF,IAAIG,QAAQ,GAAG,gBAAgB,CAAC;SAC7E,CAACf,IAAI,CAAC;IACT,EAAE,OAAM;QACN,OAAO;IACT;AACF"}
|
package/dist/util/formatSize.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/util/formatSize.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\n/**\n * Formats bytes to kB\n *\n * @internal\n */\nexport function formatSize(bytes: number): string {\n return styleText('cyan', `${(bytes / 1024).toFixed(0)} kB`)\n}\n"],"names":["styleText","formatSize","bytes","toFixed"],"mappings":"AAAA,SAAQA,SAAS,QAAO,YAAW;AAEnC;;;;CAIC,GACD,OAAO,SAASC,WAAWC,KAAa;IACtC,OAAOF,UAAU,QAAQ,GAAG,AAACE,CAAAA,QAAQ,IAAG,EAAGC,OAAO,CAAC,GAAG,GAAG,CAAC;AAC5D"}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { formatSize } from './formatSize.js';
|
|
2
|
-
export function formatModuleSizes(modules) {
|
|
3
|
-
const lines = [];
|
|
4
|
-
for (const mod of modules){
|
|
5
|
-
lines.push(` - ${formatModuleName(mod.name)} (${formatSize(mod.renderedLength)})`);
|
|
6
|
-
}
|
|
7
|
-
return lines.join('\n');
|
|
8
|
-
}
|
|
9
|
-
function formatModuleName(modName) {
|
|
10
|
-
const delimiter = '/node_modules/';
|
|
11
|
-
const nodeIndex = modName.lastIndexOf(delimiter);
|
|
12
|
-
return nodeIndex === -1 ? modName : modName.slice(nodeIndex + delimiter.length);
|
|
13
|
-
}
|
|
14
|
-
export function sortModulesBySize(chunks) {
|
|
15
|
-
return chunks.flatMap((chunk)=>chunk.modules).toSorted((modA, modB)=>modB.renderedLength - modA.renderedLength);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
//# sourceMappingURL=moduleFormatUtils.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/util/moduleFormatUtils.ts"],"sourcesContent":["import {type ChunkModule, type ChunkStats} from '../actions/build/buildStaticFiles.js'\nimport {formatSize} from './formatSize.js'\n\nexport function formatModuleSizes(modules: ChunkModule[]): string {\n const lines: string[] = []\n for (const mod of modules) {\n lines.push(` - ${formatModuleName(mod.name)} (${formatSize(mod.renderedLength)})`)\n }\n\n return lines.join('\\n')\n}\n\nfunction formatModuleName(modName: string): string {\n const delimiter = '/node_modules/'\n const nodeIndex = modName.lastIndexOf(delimiter)\n return nodeIndex === -1 ? modName : modName.slice(nodeIndex + delimiter.length)\n}\n\nexport function sortModulesBySize(chunks: ChunkStats[]): ChunkModule[] {\n return chunks\n .flatMap((chunk) => chunk.modules)\n .toSorted((modA, modB) => modB.renderedLength - modA.renderedLength)\n}\n"],"names":["formatSize","formatModuleSizes","modules","lines","mod","push","formatModuleName","name","renderedLength","join","modName","delimiter","nodeIndex","lastIndexOf","slice","length","sortModulesBySize","chunks","flatMap","chunk","toSorted","modA","modB"],"mappings":"AACA,SAAQA,UAAU,QAAO,kBAAiB;AAE1C,OAAO,SAASC,kBAAkBC,OAAsB;IACtD,MAAMC,QAAkB,EAAE;IAC1B,KAAK,MAAMC,OAAOF,QAAS;QACzBC,MAAME,IAAI,CAAC,CAAC,GAAG,EAAEC,iBAAiBF,IAAIG,IAAI,EAAE,EAAE,EAAEP,WAAWI,IAAII,cAAc,EAAE,CAAC,CAAC;IACnF;IAEA,OAAOL,MAAMM,IAAI,CAAC;AACpB;AAEA,SAASH,iBAAiBI,OAAe;IACvC,MAAMC,YAAY;IAClB,MAAMC,YAAYF,QAAQG,WAAW,CAACF;IACtC,OAAOC,cAAc,CAAC,IAAIF,UAAUA,QAAQI,KAAK,CAACF,YAAYD,UAAUI,MAAM;AAChF;AAEA,OAAO,SAASC,kBAAkBC,MAAoB;IACpD,OAAOA,OACJC,OAAO,CAAC,CAACC,QAAUA,MAAMjB,OAAO,EAChCkB,QAAQ,CAAC,CAACC,MAAMC,OAASA,KAAKd,cAAc,GAAGa,KAAKb,cAAc;AACvE"}
|