@sanity/cli-build 2.0.0 → 3.0.0

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.
@@ -1,21 +1,15 @@
1
1
  import { CliConfig } from "@sanity/cli-core";
2
+ import { CompareDependencyVersions } from "../../util/compareDependencyVersions.js";
3
+ import { CompareDependencyVersionsResult } from "../../util/compareDependencyVersions.js";
2
4
  import { ConfigEnv } from "vite";
3
- import { Debugger } from "debug";
4
- import { DefineAppInput } from "@sanity/workbench-cli";
5
- import { DefinedTelemetryTrace } from "@sanity/telemetry";
6
5
  import { FSWatcher } from "chokidar";
7
6
  import { InlineConfig } from "vite";
8
7
  import { Output } from "@sanity/cli-core";
9
8
  import { Plugin as Plugin_2 } from "vite";
10
9
  import { PluginOptions } from "babel-plugin-react-compiler";
10
+ import { UnresolvedPrerelease } from "../../util/compareDependencyVersions.js";
11
11
  import { UserViteConfig } from "@sanity/cli-core";
12
-
13
- export declare const AppBuildTrace: DefinedTelemetryTrace<
14
- {
15
- outputSize: number;
16
- },
17
- void
18
- >;
12
+ import { WorkbenchExposes } from "@sanity/workbench-cli/build";
19
13
 
20
14
  /**
21
15
  * Everything the production build needs to produce an auto-updating studio/app.
@@ -37,7 +31,71 @@ declare interface AutoUpdatesBuildConfig {
37
31
  cssUrls?: string[];
38
32
  }
39
33
 
40
- export declare const buildDebug: Debugger;
34
+ /**
35
+ * Internal build app that avoids depending on flags for CLI config.
36
+ * @param options - options for the build
37
+ */
38
+ export declare function buildApp(options: BuildOptions): Promise<void>;
39
+
40
+ declare interface BuildOptions {
41
+ appId: string | undefined;
42
+ appTitle: string | undefined;
43
+ autoUpdatesEnabled: boolean;
44
+ checkAppId: () => void;
45
+ compareDependencyVersions: (
46
+ packages: {
47
+ name: string;
48
+ version: string;
49
+ }[],
50
+ ) => Promise<CompareDependencyVersionsResult>;
51
+ determineBasePath: () => string;
52
+ entry: string | undefined;
53
+ isWorkbenchApp: boolean;
54
+ minify: boolean;
55
+ outDir: string | undefined;
56
+ output: Output;
57
+ reactCompiler: CliConfig["reactCompiler"];
58
+ schemaExtraction: CliConfig["schemaExtraction"];
59
+ sourceMap: boolean;
60
+ stats: boolean;
61
+ unattendedMode: boolean;
62
+ vite: UserViteConfig | undefined;
63
+ workDir: string;
64
+ exposes?: WorkbenchExposes;
65
+ /** The workbench app's bus identity (`__SANITY_APP_ID__`). */
66
+ workbenchAppId?: string;
67
+ }
68
+
69
+ declare interface BuildOptions_2 {
70
+ appId: string | undefined;
71
+ autoUpdatesEnabled: boolean;
72
+ checkAppId: () => void;
73
+ compareDependencyVersions: (
74
+ packages: {
75
+ name: string;
76
+ version: string;
77
+ }[],
78
+ ) => Promise<CompareDependencyVersionsResult>;
79
+ determineBasePath: () => string;
80
+ isApp: boolean;
81
+ isWorkbenchApp: boolean;
82
+ minify: boolean;
83
+ outDir: string | undefined;
84
+ output: Output;
85
+ reactCompiler: CliConfig["reactCompiler"];
86
+ schemaExtraction: CliConfig["schemaExtraction"];
87
+ sourceMap: boolean;
88
+ stats: boolean;
89
+ unattendedMode: boolean;
90
+ upgradePackages(options: {
91
+ packages: [name: string, version: string][];
92
+ }): Promise<void>;
93
+ vite: UserViteConfig | undefined;
94
+ workDir: string;
95
+ exposes?: WorkbenchExposes;
96
+ /** The workbench app's bus identity (`__SANITY_APP_ID__`). */
97
+ workbenchAppId?: string;
98
+ }
41
99
 
42
100
  /**
43
101
  * Builds static files
@@ -48,6 +106,12 @@ export declare function buildStaticFiles(options: StaticBuildOptions): Promise<{
48
106
  chunks: ChunkStats[];
49
107
  }>;
50
108
 
109
+ /**
110
+ * Internal build studio that avoids depending on flags for CLI config.
111
+ * @param options - options for the build
112
+ */
113
+ export declare function buildStudio(options: BuildOptions_2): Promise<void>;
114
+
51
115
  /**
52
116
  * Checks that the studio has declared and installed the required dependencies
53
117
  * needed by the Sanity modules. While we generally use regular, explicit
@@ -93,6 +157,10 @@ declare interface ChunkStats {
93
157
  name: string;
94
158
  }
95
159
 
160
+ export { CompareDependencyVersions };
161
+
162
+ export { CompareDependencyVersionsResult };
163
+
96
164
  /**
97
165
  * Merge user-provided Vite configuration object or function
98
166
  *
@@ -107,36 +175,6 @@ export declare function extendViteConfigWithUserConfig(
107
175
  userConfig: UserViteConfig,
108
176
  ): Promise<InlineConfig>;
109
177
 
110
- export declare function formatModuleSizes(modules: ChunkModule[]): string;
111
-
112
- /**
113
- * Generate CDN CSS URLs for auto-updated packages.
114
- * Uses the same URL pattern as JS module URLs so the module server
115
- * resolves CSS and JS to the same version.
116
- *
117
- * @internal
118
- */
119
- export declare function getAutoUpdatesCssUrls<const Pkg extends PackageWithCss>(
120
- packages: Pkg[],
121
- options?: {
122
- appId?: string;
123
- baseUrl?: string;
124
- timestamp?: number;
125
- },
126
- ): string[];
127
-
128
- /**
129
- * @internal
130
- */
131
- export declare function getAutoUpdatesImportMap<const Pkg extends Package>(
132
- packages: Pkg[],
133
- options?: {
134
- appId?: string;
135
- baseUrl?: string;
136
- timestamp?: number;
137
- },
138
- ): { [K in `${Pkg["name"]}/` | Pkg["name"]]: string };
139
-
140
178
  /**
141
179
  * @internal
142
180
  */
@@ -163,10 +201,6 @@ declare type Package = {
163
201
  version: string;
164
202
  };
165
203
 
166
- declare type PackageWithCss = Package & {
167
- cssFile?: string;
168
- };
169
-
170
204
  /**
171
205
  * Resolves vendor package entry points and metadata for a combined studio/app build.
172
206
  * Does not run a build — callers add `entries` to the main Vite/Rolldown input and
@@ -203,8 +237,6 @@ declare interface RuntimeOptions {
203
237
  */
204
238
  export declare const SANITY_CACHE_DIR = "node_modules/.sanity";
205
239
 
206
- export declare function sortModulesBySize(chunks: ChunkStats[]): ChunkModule[];
207
-
208
240
  declare interface StaticBuildOptions {
209
241
  basePath: string;
210
242
  cwd: string;
@@ -212,6 +244,7 @@ declare interface StaticBuildOptions {
212
244
  appTitle?: string;
213
245
  autoUpdates?: AutoUpdatesBuildConfig;
214
246
  entry?: string;
247
+ exposes?: WorkbenchExposes;
215
248
  isApp?: boolean;
216
249
  /** Workbench app (opted in via `unstable_defineApp`) — drives the federation build. */
217
250
  isWorkbenchApp?: boolean;
@@ -219,25 +252,20 @@ declare interface StaticBuildOptions {
219
252
  profile?: boolean;
220
253
  reactCompiler?: PluginOptions;
221
254
  schemaExtraction?: CliConfig["schemaExtraction"];
222
- services?: DefineAppInput["services"];
223
255
  sourceMap?: boolean;
224
- views?: DefineAppInput["views"];
225
256
  vite?: UserViteConfig;
257
+ /** The workbench app's bus identity (`__SANITY_APP_ID__`). */
258
+ workbenchAppId?: string;
226
259
  }
227
260
 
228
- export declare const StudioBuildTrace: DefinedTelemetryTrace<
229
- {
230
- outputSize: number;
231
- },
232
- void
233
- >;
234
-
235
261
  declare interface TrackedPackage {
236
262
  deprecatedBelow: string | null;
237
263
  name: string;
238
264
  supported: string[];
239
265
  }
240
266
 
267
+ export { UnresolvedPrerelease };
268
+
241
269
  declare interface VendorBuildConfig {
242
270
  /** Rolldown entry name -\> absolute path to the package entry file. */
243
271
  entries: Record<string, string>;
@@ -280,6 +308,7 @@ declare interface ViteOptions {
280
308
  * Will be normalized to ensure it starts and ends with a `/`
281
309
  */
282
310
  basePath?: string;
311
+ exposes?: WorkbenchExposes;
283
312
  isApp?: boolean;
284
313
  /**
285
314
  * Whether this is a workbench app (opted in via `unstable_defineApp`). Drives
@@ -305,20 +334,15 @@ declare interface ViteOptions {
305
334
  host?: string;
306
335
  port?: number;
307
336
  };
308
- /**
309
- * Background services the workbench app declares. Built into self-contained
310
- * worker bundles and exposed through module federation as `./services/<name>`.
311
- */
312
- services?: DefineAppInput["services"];
313
337
  /**
314
338
  * Whether or not to enable source maps
315
339
  */
316
340
  sourceMap?: boolean;
317
341
  /**
318
- * Views the workbench app declares. Built into render-contract artifacts and
319
- * exposed through module federation as `./views/<name>`.
342
+ * The workbench app's bus identity, stamped into its modules as
343
+ * `__SANITY_APP_ID__` for `@sanity/runtime`. Only read for workbench apps.
320
344
  */
321
- views?: DefineAppInput["views"];
345
+ workbenchAppId?: string;
322
346
  }
323
347
 
324
348
  /**
@@ -1,13 +1,12 @@
1
- export { buildDebug } from '../../actions/build/buildDebug.js';
1
+ export { buildApp } from '../../actions/build/buildApp.js';
2
2
  export { buildStaticFiles } from '../../actions/build/buildStaticFiles.js';
3
+ export { buildStudio } from '../../actions/build/buildStudio.js';
3
4
  export { checkRequiredDependencies } from '../../actions/build/checkRequiredDependencies.js';
4
5
  export { checkStudioDependencyVersions } from '../../actions/build/checkStudioDependencyVersions.js';
5
- export { getAutoUpdatesCssUrls, getAutoUpdatesImportMap, getModuleUrl } from '../../actions/build/getAutoUpdatesImportMap.js';
6
+ export { getModuleUrl } from '../../actions/build/getAutoUpdatesImportMap.js';
6
7
  export { extendViteConfigWithUserConfig, getViteConfig } from '../../actions/build/getViteConfig.js';
7
8
  export { resolveVendorBuildConfig } from '../../actions/build/resolveVendorBuildConfig.js';
8
9
  export { writeSanityRuntime } from '../../actions/build/writeSanityRuntime.js';
9
10
  export { SANITY_CACHE_DIR } from '../../constants.js';
10
- export { AppBuildTrace, StudioBuildTrace } from '../../telemetry/build.telemetry.js';
11
- export { formatModuleSizes, sortModulesBySize } from '../../util/moduleFormatUtils.js';
12
11
 
13
12
  //# sourceMappingURL=build.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/_exports/_internal/build.ts"],"sourcesContent":["export {buildDebug} from '../../actions/build/buildDebug.js'\nexport {buildStaticFiles} from '../../actions/build/buildStaticFiles.js'\nexport {checkRequiredDependencies} from '../../actions/build/checkRequiredDependencies.js'\nexport {checkStudioDependencyVersions} from '../../actions/build/checkStudioDependencyVersions.js'\nexport {\n getAutoUpdatesCssUrls,\n getAutoUpdatesImportMap,\n getModuleUrl,\n} from '../../actions/build/getAutoUpdatesImportMap.js'\nexport {extendViteConfigWithUserConfig, getViteConfig} from '../../actions/build/getViteConfig.js'\nexport {resolveVendorBuildConfig} from '../../actions/build/resolveVendorBuildConfig.js'\nexport {writeSanityRuntime} from '../../actions/build/writeSanityRuntime.js'\nexport {SANITY_CACHE_DIR} from '../../constants.js'\nexport {AppBuildTrace, StudioBuildTrace} from '../../telemetry/build.telemetry.js'\nexport {formatModuleSizes, sortModulesBySize} from '../../util/moduleFormatUtils.js'\n"],"names":["buildDebug","buildStaticFiles","checkRequiredDependencies","checkStudioDependencyVersions","getAutoUpdatesCssUrls","getAutoUpdatesImportMap","getModuleUrl","extendViteConfigWithUserConfig","getViteConfig","resolveVendorBuildConfig","writeSanityRuntime","SANITY_CACHE_DIR","AppBuildTrace","StudioBuildTrace","formatModuleSizes","sortModulesBySize"],"mappings":"AAAA,SAAQA,UAAU,QAAO,oCAAmC;AAC5D,SAAQC,gBAAgB,QAAO,0CAAyC;AACxE,SAAQC,yBAAyB,QAAO,mDAAkD;AAC1F,SAAQC,6BAA6B,QAAO,uDAAsD;AAClG,SACEC,qBAAqB,EACrBC,uBAAuB,EACvBC,YAAY,QACP,iDAAgD;AACvD,SAAQC,8BAA8B,EAAEC,aAAa,QAAO,uCAAsC;AAClG,SAAQC,wBAAwB,QAAO,kDAAiD;AACxF,SAAQC,kBAAkB,QAAO,4CAA2C;AAC5E,SAAQC,gBAAgB,QAAO,qBAAoB;AACnD,SAAQC,aAAa,EAAEC,gBAAgB,QAAO,qCAAoC;AAClF,SAAQC,iBAAiB,EAAEC,iBAAiB,QAAO,kCAAiC"}
1
+ {"version":3,"sources":["../../../src/_exports/_internal/build.ts"],"sourcesContent":["export {buildApp} from '../../actions/build/buildApp.js'\nexport {buildStaticFiles} from '../../actions/build/buildStaticFiles.js'\nexport {buildStudio} from '../../actions/build/buildStudio.js'\nexport {checkRequiredDependencies} from '../../actions/build/checkRequiredDependencies.js'\nexport {checkStudioDependencyVersions} from '../../actions/build/checkStudioDependencyVersions.js'\nexport {getModuleUrl} from '../../actions/build/getAutoUpdatesImportMap.js'\nexport {extendViteConfigWithUserConfig, getViteConfig} from '../../actions/build/getViteConfig.js'\nexport {resolveVendorBuildConfig} from '../../actions/build/resolveVendorBuildConfig.js'\nexport {writeSanityRuntime} from '../../actions/build/writeSanityRuntime.js'\nexport {SANITY_CACHE_DIR} from '../../constants.js'\nexport type {\n CompareDependencyVersions,\n CompareDependencyVersionsResult,\n UnresolvedPrerelease,\n} from '../../util/compareDependencyVersions.js'\n"],"names":["buildApp","buildStaticFiles","buildStudio","checkRequiredDependencies","checkStudioDependencyVersions","getModuleUrl","extendViteConfigWithUserConfig","getViteConfig","resolveVendorBuildConfig","writeSanityRuntime","SANITY_CACHE_DIR"],"mappings":"AAAA,SAAQA,QAAQ,QAAO,kCAAiC;AACxD,SAAQC,gBAAgB,QAAO,0CAAyC;AACxE,SAAQC,WAAW,QAAO,qCAAoC;AAC9D,SAAQC,yBAAyB,QAAO,mDAAkD;AAC1F,SAAQC,6BAA6B,QAAO,uDAAsD;AAClG,SAAQC,YAAY,QAAO,iDAAgD;AAC3E,SAAQC,8BAA8B,EAAEC,aAAa,QAAO,uCAAsC;AAClG,SAAQC,wBAAwB,QAAO,kDAAiD;AACxF,SAAQC,kBAAkB,QAAO,4CAA2C;AAC5E,SAAQC,gBAAgB,QAAO,qBAAoB"}
@@ -0,0 +1,188 @@
1
+ import { rm } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { styleText } from 'node:util';
4
+ import { getCliTelemetry, getLocalPackageVersion, getTimer, isInteractive } from '@sanity/cli-core';
5
+ import { confirm, logSymbols, spinner } from '@sanity/cli-core/ux';
6
+ import { parse as semverParse } from 'semver';
7
+ import { AppBuildTrace } from '../../telemetry/build.telemetry.js';
8
+ import { formatModuleSizes, sortModulesBySize } from '../../util/moduleFormatUtils.js';
9
+ import { buildDebug } from './buildDebug.js';
10
+ import { buildStaticFiles } from './buildStaticFiles.js';
11
+ import { getAutoUpdatesCssUrls, getAutoUpdatesImportMap } from './getAutoUpdatesImportMap.js';
12
+ import { getAppEnvironmentVariables } from './getEnvironmentVariables.js';
13
+ import { handlePrereleaseVersions } from './handlePrereleaseVersions.js';
14
+ import { resolveVendorBuildConfig } from './resolveVendorBuildConfig.js';
15
+ /**
16
+ * Internal build app that avoids depending on flags for CLI config.
17
+ * @param options - options for the build
18
+ */ export async function buildApp(options) {
19
+ buildDebug(`Building app`);
20
+ const { appId, determineBasePath, outDir, output, workDir } = options;
21
+ let { autoUpdatesEnabled } = options;
22
+ const unattendedMode = options.unattendedMode;
23
+ const timer = getTimer();
24
+ const defaultOutputDir = path.resolve(path.join(workDir, 'dist'));
25
+ const outputDir = path.resolve(outDir || defaultOutputDir);
26
+ const installedSdkVersion = await getLocalPackageVersion('@sanity/sdk-react', workDir);
27
+ const installedSanityVersion = await getLocalPackageVersion('sanity', workDir);
28
+ if (!installedSdkVersion) {
29
+ output.error(`Failed to find installed @sanity/sdk-react version`, {
30
+ exit: 1
31
+ });
32
+ return;
33
+ }
34
+ let autoUpdatesImports = {};
35
+ let autoUpdatesCssUrls = [];
36
+ if (autoUpdatesEnabled) {
37
+ // Get the clean version without build metadata: https://semver.org/#spec-item-10
38
+ const cleanSDKVersion = semverParse(installedSdkVersion)?.version;
39
+ if (!cleanSDKVersion) {
40
+ output.error(`Failed to parse installed SDK version: ${installedSdkVersion}`, {
41
+ exit: 1
42
+ });
43
+ return;
44
+ }
45
+ // Sanity might not be installed, but if it is, we want to auto update it.
46
+ const cleanSanityVersion = semverParse(installedSanityVersion)?.version;
47
+ const autoUpdatedPackages = [
48
+ {
49
+ name: '@sanity/sdk',
50
+ version: cleanSDKVersion
51
+ },
52
+ {
53
+ name: '@sanity/sdk-react',
54
+ version: cleanSDKVersion
55
+ },
56
+ ...cleanSanityVersion ? [
57
+ {
58
+ cssFile: 'index.css',
59
+ name: 'sanity',
60
+ version: cleanSanityVersion
61
+ }
62
+ ] : []
63
+ ];
64
+ autoUpdatesImports = getAutoUpdatesImportMap(autoUpdatedPackages, {
65
+ appId
66
+ });
67
+ autoUpdatesCssUrls = getAutoUpdatesCssUrls(autoUpdatedPackages, {
68
+ appId
69
+ });
70
+ output.log(`${logSymbols.info} Building with auto-updates enabled`);
71
+ // Warn if auto updates enabled but no appId configured.
72
+ options.checkAppId();
73
+ // Check the versions
74
+ const { mismatched, unresolvedPrerelease } = await options.compareDependencyVersions(autoUpdatedPackages);
75
+ if (unresolvedPrerelease.length > 0) {
76
+ await handlePrereleaseVersions({
77
+ output,
78
+ unattendedMode,
79
+ unresolvedPrerelease
80
+ });
81
+ autoUpdatesImports = {};
82
+ autoUpdatesCssUrls = [];
83
+ autoUpdatesEnabled = false;
84
+ }
85
+ if (mismatched.length > 0 && autoUpdatesEnabled) {
86
+ const versionMismatchWarning = `The following local package versions are different from the versions currently served at runtime.\n` + `When using auto updates, we recommend that you test locally with the same versions before deploying. \n\n` + `${mismatched.map((mod)=>` - ${mod.pkg} (local version: ${mod.installed}, runtime version: ${mod.remote})`).join('\n')}`;
87
+ // If it is non-interactive or in unattended mode, we don't want to prompt
88
+ if (isInteractive() && !unattendedMode) {
89
+ const shouldContinue = await confirm({
90
+ default: false,
91
+ message: styleText('yellow', `${versionMismatchWarning} \n\nContinue anyway?`)
92
+ });
93
+ if (!shouldContinue) {
94
+ output.error('Declined to continue with build', {
95
+ exit: 1
96
+ });
97
+ return;
98
+ }
99
+ } else {
100
+ // if non-interactive or unattended, just show the warning
101
+ output.warn(versionMismatchWarning);
102
+ }
103
+ }
104
+ }
105
+ const envVarKeys = Object.keys(getAppEnvironmentVariables());
106
+ if (envVarKeys.length > 0) {
107
+ output.log('\nIncluding the following environment variables as part of the JavaScript bundle:');
108
+ for (const key of envVarKeys)output.log(`- ${key}`);
109
+ output.log('');
110
+ }
111
+ let shouldClean = true;
112
+ if (outputDir !== defaultOutputDir && !unattendedMode && isInteractive()) {
113
+ shouldClean = await confirm({
114
+ default: true,
115
+ message: `Do you want to delete the existing directory (${outputDir}) first?`
116
+ });
117
+ }
118
+ const basePath = determineBasePath();
119
+ let spin;
120
+ if (shouldClean) {
121
+ timer.start('cleanOutputFolder');
122
+ spin = spinner('Clean output folder').start();
123
+ await rm(outputDir, {
124
+ force: true,
125
+ recursive: true
126
+ });
127
+ const cleanDuration = timer.end('cleanOutputFolder');
128
+ spin.text = `Clean output folder (${cleanDuration.toFixed(0)}ms)`;
129
+ spin.succeed();
130
+ }
131
+ spin = spinner(`Building Sanity application`).start();
132
+ const trace = getCliTelemetry().trace(AppBuildTrace);
133
+ trace.start();
134
+ let autoUpdates;
135
+ if (autoUpdatesEnabled && !options.isWorkbenchApp) {
136
+ autoUpdates = {
137
+ cssUrls: autoUpdatesCssUrls,
138
+ imports: autoUpdatesImports,
139
+ vendor: await resolveVendorBuildConfig({
140
+ cwd: workDir,
141
+ isApp: true
142
+ })
143
+ };
144
+ }
145
+ try {
146
+ timer.start('bundleStudio');
147
+ const bundle = await buildStaticFiles({
148
+ appTitle: options.appTitle,
149
+ autoUpdates,
150
+ basePath,
151
+ cwd: workDir,
152
+ entry: options.entry,
153
+ exposes: options.exposes,
154
+ isApp: true,
155
+ isWorkbenchApp: options.isWorkbenchApp,
156
+ minify: options.minify,
157
+ outputDir,
158
+ reactCompiler: options.reactCompiler,
159
+ schemaExtraction: options.schemaExtraction,
160
+ sourceMap: options.sourceMap,
161
+ vite: options.vite,
162
+ workbenchAppId: options.workbenchAppId
163
+ });
164
+ trace.log({
165
+ outputSize: bundle.chunks.flatMap((chunk)=>chunk.modules.flatMap((mod)=>mod.renderedLength)).reduce((sum, n)=>sum + n, 0)
166
+ });
167
+ const buildDuration = timer.end('bundleStudio');
168
+ spin.text = `Build Sanity application (${buildDuration.toFixed(0)}ms)`;
169
+ spin.succeed();
170
+ if (options.stats) {
171
+ output.log('\nLargest module files:');
172
+ output.log(formatModuleSizes(sortModulesBySize(bundle.chunks).slice(0, 15)));
173
+ }
174
+ trace.complete();
175
+ } catch (error) {
176
+ spin.fail();
177
+ trace.error(error);
178
+ const message = error instanceof Error ? error.message : String(error);
179
+ buildDebug(`Failed to build Sanity application`, {
180
+ error
181
+ });
182
+ output.error(`Failed to build Sanity application: ${message}`, {
183
+ exit: 1
184
+ });
185
+ }
186
+ }
187
+
188
+ //# sourceMappingURL=buildApp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/actions/build/buildApp.ts"],"sourcesContent":["import {rm} from 'node:fs/promises'\nimport path from 'node:path'\nimport {styleText} from 'node:util'\n\nimport {\n type CliConfig,\n getCliTelemetry,\n getLocalPackageVersion,\n getTimer,\n isInteractive,\n type Output,\n type UserViteConfig,\n} from '@sanity/cli-core'\nimport {confirm, logSymbols, spinner, type SpinnerInstance} from '@sanity/cli-core/ux'\nimport {type WorkbenchExposes} from '@sanity/workbench-cli/build'\nimport {parse as semverParse} from 'semver'\n\nimport {AppBuildTrace} from '../../telemetry/build.telemetry.js'\nimport {CompareDependencyVersionsResult} from '../../util/compareDependencyVersions.js'\nimport {formatModuleSizes, sortModulesBySize} from '../../util/moduleFormatUtils.js'\nimport {buildDebug} from './buildDebug.js'\nimport {buildStaticFiles} from './buildStaticFiles.js'\nimport {getAutoUpdatesCssUrls, getAutoUpdatesImportMap} from './getAutoUpdatesImportMap.js'\nimport {getAppEnvironmentVariables} from './getEnvironmentVariables.js'\nimport {handlePrereleaseVersions} from './handlePrereleaseVersions.js'\nimport {resolveVendorBuildConfig} from './resolveVendorBuildConfig.js'\n\nexport interface BuildOptions {\n appId: string | undefined\n appTitle: string | undefined\n autoUpdatesEnabled: boolean\n checkAppId: () => void\n compareDependencyVersions: (\n packages: {name: string; version: string}[],\n ) => Promise<CompareDependencyVersionsResult>\n determineBasePath: () => string\n entry: string | undefined\n isWorkbenchApp: boolean\n minify: boolean\n outDir: string | undefined\n output: Output\n reactCompiler: CliConfig['reactCompiler']\n schemaExtraction: CliConfig['schemaExtraction']\n sourceMap: boolean\n stats: boolean\n unattendedMode: boolean\n vite: UserViteConfig | undefined\n workDir: string\n\n exposes?: WorkbenchExposes\n\n /** The workbench app's bus identity (`__SANITY_APP_ID__`). */\n workbenchAppId?: string\n}\n\n/**\n * Internal build app that avoids depending on flags for CLI config.\n * @param options - options for the build\n */\nexport async function buildApp(options: BuildOptions): Promise<void> {\n buildDebug(`Building app`)\n\n const {appId, determineBasePath, outDir, output, workDir} = options\n let {autoUpdatesEnabled} = options\n const unattendedMode = options.unattendedMode\n\n const timer = getTimer()\n\n const defaultOutputDir = path.resolve(path.join(workDir, 'dist'))\n const outputDir = path.resolve(outDir || defaultOutputDir)\n\n const installedSdkVersion = await getLocalPackageVersion('@sanity/sdk-react', workDir)\n const installedSanityVersion = await getLocalPackageVersion('sanity', workDir)\n\n if (!installedSdkVersion) {\n output.error(`Failed to find installed @sanity/sdk-react version`, {exit: 1})\n return\n }\n\n let autoUpdatesImports = {}\n let autoUpdatesCssUrls: string[] = []\n\n if (autoUpdatesEnabled) {\n // Get the clean version without build metadata: https://semver.org/#spec-item-10\n const cleanSDKVersion = semverParse(installedSdkVersion)?.version\n if (!cleanSDKVersion) {\n output.error(`Failed to parse installed SDK version: ${installedSdkVersion}`, {exit: 1})\n return\n }\n\n // Sanity might not be installed, but if it is, we want to auto update it.\n const cleanSanityVersion = semverParse(installedSanityVersion)?.version\n\n const autoUpdatedPackages = [\n {name: '@sanity/sdk', version: cleanSDKVersion},\n {name: '@sanity/sdk-react', version: cleanSDKVersion},\n ...(cleanSanityVersion\n ? [{cssFile: 'index.css', name: 'sanity' as const, version: cleanSanityVersion}]\n : []),\n ]\n autoUpdatesImports = getAutoUpdatesImportMap(autoUpdatedPackages, {appId})\n autoUpdatesCssUrls = getAutoUpdatesCssUrls(autoUpdatedPackages, {appId})\n\n output.log(`${logSymbols.info} Building with auto-updates enabled`)\n\n // Warn if auto updates enabled but no appId configured.\n options.checkAppId()\n\n // Check the versions\n const {mismatched, unresolvedPrerelease} =\n await options.compareDependencyVersions(autoUpdatedPackages)\n\n if (unresolvedPrerelease.length > 0) {\n await handlePrereleaseVersions({output, unattendedMode, unresolvedPrerelease})\n autoUpdatesImports = {}\n autoUpdatesCssUrls = []\n autoUpdatesEnabled = false\n }\n\n if (mismatched.length > 0 && autoUpdatesEnabled) {\n const versionMismatchWarning =\n `The following local package versions are different from the versions currently served at runtime.\\n` +\n `When using auto updates, we recommend that you test locally with the same versions before deploying. \\n\\n` +\n `${mismatched.map((mod) => ` - ${mod.pkg} (local version: ${mod.installed}, runtime version: ${mod.remote})`).join('\\n')}`\n\n // If it is non-interactive or in unattended mode, we don't want to prompt\n if (isInteractive() && !unattendedMode) {\n const shouldContinue = await confirm({\n default: false,\n message: styleText('yellow', `${versionMismatchWarning} \\n\\nContinue anyway?`),\n })\n\n if (!shouldContinue) {\n output.error('Declined to continue with build', {exit: 1})\n return\n }\n } else {\n // if non-interactive or unattended, just show the warning\n output.warn(versionMismatchWarning)\n }\n }\n }\n\n const envVarKeys = Object.keys(getAppEnvironmentVariables())\n if (envVarKeys.length > 0) {\n output.log('\\nIncluding the following environment variables as part of the JavaScript bundle:')\n for (const key of envVarKeys) output.log(`- ${key}`)\n output.log('')\n }\n\n let shouldClean = true\n if (outputDir !== defaultOutputDir && !unattendedMode && isInteractive()) {\n shouldClean = await confirm({\n default: true,\n message: `Do you want to delete the existing directory (${outputDir}) first?`,\n })\n }\n\n const basePath = determineBasePath()\n\n let spin: SpinnerInstance\n if (shouldClean) {\n timer.start('cleanOutputFolder')\n spin = spinner('Clean output folder').start()\n await rm(outputDir, {force: true, recursive: true})\n const cleanDuration = timer.end('cleanOutputFolder')\n spin.text = `Clean output folder (${cleanDuration.toFixed(0)}ms)`\n spin.succeed()\n }\n\n spin = spinner(`Building Sanity application`).start()\n\n const trace = getCliTelemetry().trace(AppBuildTrace)\n trace.start()\n\n let autoUpdates\n if (autoUpdatesEnabled && !options.isWorkbenchApp) {\n autoUpdates = {\n cssUrls: autoUpdatesCssUrls,\n imports: autoUpdatesImports,\n vendor: await resolveVendorBuildConfig({cwd: workDir, isApp: true}),\n }\n }\n\n try {\n timer.start('bundleStudio')\n\n const bundle = await buildStaticFiles({\n appTitle: options.appTitle,\n autoUpdates,\n basePath,\n cwd: workDir,\n entry: options.entry,\n exposes: options.exposes,\n isApp: true,\n isWorkbenchApp: options.isWorkbenchApp,\n minify: options.minify,\n outputDir,\n reactCompiler: options.reactCompiler,\n schemaExtraction: options.schemaExtraction,\n sourceMap: options.sourceMap,\n vite: options.vite,\n workbenchAppId: options.workbenchAppId,\n })\n\n trace.log({\n outputSize: bundle.chunks\n .flatMap((chunk) => chunk.modules.flatMap((mod) => mod.renderedLength))\n .reduce((sum, n) => sum + n, 0),\n })\n const buildDuration = timer.end('bundleStudio')\n\n spin.text = `Build Sanity application (${buildDuration.toFixed(0)}ms)`\n spin.succeed()\n\n if (options.stats) {\n output.log('\\nLargest module files:')\n output.log(formatModuleSizes(sortModulesBySize(bundle.chunks).slice(0, 15)))\n }\n\n trace.complete()\n } catch (error) {\n spin.fail()\n trace.error(error)\n const message = error instanceof Error ? error.message : String(error)\n buildDebug(`Failed to build Sanity application`, {error})\n output.error(`Failed to build Sanity application: ${message}`, {exit: 1})\n }\n}\n"],"names":["rm","path","styleText","getCliTelemetry","getLocalPackageVersion","getTimer","isInteractive","confirm","logSymbols","spinner","parse","semverParse","AppBuildTrace","formatModuleSizes","sortModulesBySize","buildDebug","buildStaticFiles","getAutoUpdatesCssUrls","getAutoUpdatesImportMap","getAppEnvironmentVariables","handlePrereleaseVersions","resolveVendorBuildConfig","buildApp","options","appId","determineBasePath","outDir","output","workDir","autoUpdatesEnabled","unattendedMode","timer","defaultOutputDir","resolve","join","outputDir","installedSdkVersion","installedSanityVersion","error","exit","autoUpdatesImports","autoUpdatesCssUrls","cleanSDKVersion","version","cleanSanityVersion","autoUpdatedPackages","name","cssFile","log","info","checkAppId","mismatched","unresolvedPrerelease","compareDependencyVersions","length","versionMismatchWarning","map","mod","pkg","installed","remote","shouldContinue","default","message","warn","envVarKeys","Object","keys","key","shouldClean","basePath","spin","start","force","recursive","cleanDuration","end","text","toFixed","succeed","trace","autoUpdates","isWorkbenchApp","cssUrls","imports","vendor","cwd","isApp","bundle","appTitle","entry","exposes","minify","reactCompiler","schemaExtraction","sourceMap","vite","workbenchAppId","outputSize","chunks","flatMap","chunk","modules","renderedLength","reduce","sum","n","buildDuration","stats","slice","complete","fail","Error","String"],"mappings":"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"}
@@ -11,7 +11,7 @@ import { resolveEntries, writeSanityRuntime } from './writeSanityRuntime.js';
11
11
  *
12
12
  * @internal
13
13
  */ export async function buildStaticFiles(options) {
14
- const { appTitle, autoUpdates, basePath, cwd, entry, isApp, isWorkbenchApp, minify = true, outputDir, reactCompiler, schemaExtraction, services, sourceMap = false, views, vite: extendViteConfig } = options;
14
+ const { appTitle, autoUpdates, basePath, cwd, entry, exposes, isApp, isWorkbenchApp, minify = true, outputDir, reactCompiler, schemaExtraction, sourceMap = false, vite: extendViteConfig, workbenchAppId } = options;
15
15
  const mode = 'production';
16
16
  /* Federation builds only produce the federation environment
17
17
  * (remote-entry, mf-manifest) — skip client-specific steps like
@@ -29,6 +29,7 @@ import { resolveEntries, writeSanityRuntime } from './writeSanityRuntime.js';
29
29
  basePath,
30
30
  cwd,
31
31
  entries,
32
+ exposes,
32
33
  getEnvironmentVariables,
33
34
  isApp,
34
35
  isWorkbenchApp,
@@ -39,9 +40,8 @@ import { resolveEntries, writeSanityRuntime } from './writeSanityRuntime.js';
39
40
  // Schema extraction is a build-time artifact, not a client-specific step,
40
41
  // so a federated studio extracts its schema like the legacy studio build.
41
42
  schemaExtraction,
42
- services,
43
43
  sourceMap,
44
- views
44
+ workbenchAppId
45
45
  });
46
46
  // Apply the user's Vite config so plugins like `@vanilla-extract/vite-plugin`
47
47
  // transform source files before the federation environment is bundled.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/build/buildStaticFiles.ts"],"sourcesContent":["import path from 'node:path'\n\nimport {type CliConfig, type UserViteConfig} from '@sanity/cli-core'\nimport {type DefineAppInput} from '@sanity/workbench-cli'\nimport {type PluginOptions as ReactCompilerConfig} from 'babel-plugin-react-compiler'\nimport {build, createBuilder} from 'vite'\n\nimport {copyDir} from '../../util/copyDir.js'\nimport {type AutoUpdatesBuildConfig} from './autoUpdates.js'\nimport {buildDebug} from './buildDebug.js'\nimport {\n getAppEnvironmentVariables,\n getStudioEnvironmentVariables,\n} from './getEnvironmentVariables.js'\nimport {extendViteConfigWithUserConfig, finalizeViteConfig, getViteConfig} from './getViteConfig.js'\nimport {writeFavicons} from './writeFavicons.js'\nimport {resolveEntries, writeSanityRuntime} from './writeSanityRuntime.js'\n\nexport interface ChunkModule {\n name: string\n renderedLength: number\n}\n\nexport interface ChunkStats {\n modules: ChunkModule[]\n name: string\n}\n\ninterface StaticBuildOptions {\n basePath: string\n cwd: string\n outputDir: string\n\n appTitle?: string\n autoUpdates?: AutoUpdatesBuildConfig\n entry?: string\n isApp?: boolean\n /** Workbench app (opted in via `unstable_defineApp`) — drives the federation build. */\n isWorkbenchApp?: boolean\n minify?: boolean\n profile?: boolean\n reactCompiler?: ReactCompilerConfig\n schemaExtraction?: CliConfig['schemaExtraction']\n services?: DefineAppInput['services']\n sourceMap?: boolean\n views?: DefineAppInput['views']\n vite?: UserViteConfig\n}\n\n/**\n * Builds static files\n *\n * @internal\n */\nexport async function buildStaticFiles(\n options: StaticBuildOptions,\n): Promise<{chunks: ChunkStats[]}> {\n const {\n appTitle,\n autoUpdates,\n basePath,\n cwd,\n entry,\n isApp,\n isWorkbenchApp,\n minify = true,\n outputDir,\n reactCompiler,\n schemaExtraction,\n services,\n sourceMap = false,\n views,\n vite: extendViteConfig,\n } = options\n\n const mode = 'production'\n\n /* Federation builds only produce the federation environment\n * (remote-entry, mf-manifest) — skip client-specific steps like\n * runtime generation, static file copies, and favicons.\n */\n if (isWorkbenchApp) {\n buildDebug('Resolving entries for federation build')\n const entries = await resolveEntries({cwd, entry, isApp, isWorkbenchApp})\n\n buildDebug('Resolving vite config (federation)')\n let viteConfig = await getViteConfig({\n basePath,\n cwd,\n entries,\n getEnvironmentVariables,\n isApp,\n isWorkbenchApp,\n minify,\n mode,\n outputDir,\n reactCompiler,\n // Schema extraction is a build-time artifact, not a client-specific step,\n // so a federated studio extracts its schema like the legacy studio build.\n schemaExtraction,\n services,\n sourceMap,\n views,\n })\n\n // Apply the user's Vite config so plugins like `@vanilla-extract/vite-plugin`\n // transform source files before the federation environment is bundled.\n // `finalizeViteConfig` is intentionally skipped: the federation environment\n // has its own entry and does not use `.sanity/runtime/app.js`.\n if (extendViteConfig) {\n viteConfig = await extendViteConfigWithUserConfig(\n {command: 'build', mode},\n viteConfig,\n extendViteConfig,\n )\n }\n\n buildDebug('Bundling federation environment')\n const builder = await createBuilder(viteConfig)\n await builder.buildApp()\n buildDebug('Bundling complete')\n // TODO: add stats here\n return {chunks: []}\n }\n\n buildDebug('Writing Sanity runtime files')\n const {entries} = await writeSanityRuntime({\n appTitle,\n basePath,\n cwd,\n entry,\n isApp,\n isWorkbenchApp,\n reactStrictMode: false,\n watch: false,\n })\n\n function getEnvironmentVariables() {\n return isApp\n ? getAppEnvironmentVariables({jsonEncode: true, prefix: 'process.env.'})\n : getStudioEnvironmentVariables({jsonEncode: true, prefix: 'process.env.'})\n }\n\n buildDebug('Resolving vite config')\n let viteConfig = await getViteConfig({\n autoUpdates,\n basePath,\n cwd,\n entries,\n getEnvironmentVariables,\n isApp,\n isWorkbenchApp,\n minify,\n mode,\n outputDir,\n reactCompiler,\n schemaExtraction,\n sourceMap,\n })\n\n if (extendViteConfig) {\n const defaultViteConfig = viteConfig\n viteConfig = await extendViteConfigWithUserConfig(\n {command: 'build', mode},\n viteConfig,\n extendViteConfig,\n )\n viteConfig = await finalizeViteConfig(viteConfig, defaultViteConfig)\n }\n\n const fromPath = path.join(cwd, 'static')\n // Copy files placed in /static to the built /static\n buildDebug(`Copying static files from ${fromPath} to output dir`)\n const staticPath = path.join(outputDir, 'static')\n await copyDir(fromPath, staticPath)\n\n // Write favicons, not overwriting ones that already exist, to static folder\n buildDebug('Writing favicons to output dir')\n const faviconBasePath = `${basePath.replace(/\\/+$/, '')}/static`\n await writeFavicons(faviconBasePath, staticPath)\n\n buildDebug('Bundling using vite')\n const bundle = await build(viteConfig)\n buildDebug('Bundling complete')\n\n // For typescript only - this shouldn't ever be the case given we're not watching\n if (Array.isArray(bundle) || !('output' in bundle)) {\n return {chunks: []}\n }\n\n const stats: ChunkStats[] = []\n for (const chunk of bundle.output) {\n if (chunk.type !== 'chunk') {\n continue\n }\n\n stats.push({\n modules: Object.entries(chunk.modules).map(([rawFilePath, chunkModule]) => {\n const filePath = rawFilePath.startsWith('\\u0000')\n ? rawFilePath.slice('\\u0000'.length)\n : rawFilePath\n\n return {\n name: path.isAbsolute(filePath) ? path.relative(cwd, filePath) : filePath,\n renderedLength: chunkModule.renderedLength,\n }\n }),\n name: chunk.name,\n })\n }\n\n return {chunks: stats}\n}\n"],"names":["path","build","createBuilder","copyDir","buildDebug","getAppEnvironmentVariables","getStudioEnvironmentVariables","extendViteConfigWithUserConfig","finalizeViteConfig","getViteConfig","writeFavicons","resolveEntries","writeSanityRuntime","buildStaticFiles","options","appTitle","autoUpdates","basePath","cwd","entry","isApp","isWorkbenchApp","minify","outputDir","reactCompiler","schemaExtraction","services","sourceMap","views","vite","extendViteConfig","mode","entries","viteConfig","getEnvironmentVariables","command","builder","buildApp","chunks","reactStrictMode","watch","jsonEncode","prefix","defaultViteConfig","fromPath","join","staticPath","faviconBasePath","replace","bundle","Array","isArray","stats","chunk","output","type","push","modules","Object","map","rawFilePath","chunkModule","filePath","startsWith","slice","length","name","isAbsolute","relative","renderedLength"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/actions/build/buildStaticFiles.ts"],"sourcesContent":["import path from 'node:path'\n\nimport {type CliConfig, type UserViteConfig} from '@sanity/cli-core'\nimport {type WorkbenchExposes} from '@sanity/workbench-cli/build'\nimport {type PluginOptions as ReactCompilerConfig} from 'babel-plugin-react-compiler'\nimport {build, createBuilder} from 'vite'\n\nimport {copyDir} from '../../util/copyDir.js'\nimport {type AutoUpdatesBuildConfig} from './autoUpdates.js'\nimport {buildDebug} from './buildDebug.js'\nimport {\n getAppEnvironmentVariables,\n getStudioEnvironmentVariables,\n} from './getEnvironmentVariables.js'\nimport {extendViteConfigWithUserConfig, finalizeViteConfig, getViteConfig} from './getViteConfig.js'\nimport {writeFavicons} from './writeFavicons.js'\nimport {resolveEntries, writeSanityRuntime} from './writeSanityRuntime.js'\n\nexport interface ChunkModule {\n name: string\n renderedLength: number\n}\n\nexport interface ChunkStats {\n modules: ChunkModule[]\n name: string\n}\n\ninterface StaticBuildOptions {\n basePath: string\n cwd: string\n outputDir: string\n\n appTitle?: string\n autoUpdates?: AutoUpdatesBuildConfig\n entry?: string\n exposes?: WorkbenchExposes\n isApp?: boolean\n /** Workbench app (opted in via `unstable_defineApp`) — drives the federation build. */\n isWorkbenchApp?: boolean\n minify?: boolean\n profile?: boolean\n reactCompiler?: ReactCompilerConfig\n schemaExtraction?: CliConfig['schemaExtraction']\n sourceMap?: boolean\n vite?: UserViteConfig\n /** The workbench app's bus identity (`__SANITY_APP_ID__`). */\n workbenchAppId?: string\n}\n\n/**\n * Builds static files\n *\n * @internal\n */\nexport async function buildStaticFiles(\n options: StaticBuildOptions,\n): Promise<{chunks: ChunkStats[]}> {\n const {\n appTitle,\n autoUpdates,\n basePath,\n cwd,\n entry,\n exposes,\n isApp,\n isWorkbenchApp,\n minify = true,\n outputDir,\n reactCompiler,\n schemaExtraction,\n sourceMap = false,\n vite: extendViteConfig,\n workbenchAppId,\n } = options\n\n const mode = 'production'\n\n /* Federation builds only produce the federation environment\n * (remote-entry, mf-manifest) — skip client-specific steps like\n * runtime generation, static file copies, and favicons.\n */\n if (isWorkbenchApp) {\n buildDebug('Resolving entries for federation build')\n const entries = await resolveEntries({cwd, entry, isApp, isWorkbenchApp})\n\n buildDebug('Resolving vite config (federation)')\n let viteConfig = await getViteConfig({\n basePath,\n cwd,\n entries,\n exposes,\n getEnvironmentVariables,\n isApp,\n isWorkbenchApp,\n minify,\n mode,\n outputDir,\n reactCompiler,\n // Schema extraction is a build-time artifact, not a client-specific step,\n // so a federated studio extracts its schema like the legacy studio build.\n schemaExtraction,\n sourceMap,\n workbenchAppId,\n })\n\n // Apply the user's Vite config so plugins like `@vanilla-extract/vite-plugin`\n // transform source files before the federation environment is bundled.\n // `finalizeViteConfig` is intentionally skipped: the federation environment\n // has its own entry and does not use `.sanity/runtime/app.js`.\n if (extendViteConfig) {\n viteConfig = await extendViteConfigWithUserConfig(\n {command: 'build', mode},\n viteConfig,\n extendViteConfig,\n )\n }\n\n buildDebug('Bundling federation environment')\n const builder = await createBuilder(viteConfig)\n await builder.buildApp()\n buildDebug('Bundling complete')\n // TODO: add stats here\n return {chunks: []}\n }\n\n buildDebug('Writing Sanity runtime files')\n const {entries} = await writeSanityRuntime({\n appTitle,\n basePath,\n cwd,\n entry,\n isApp,\n isWorkbenchApp,\n reactStrictMode: false,\n watch: false,\n })\n\n function getEnvironmentVariables() {\n return isApp\n ? getAppEnvironmentVariables({jsonEncode: true, prefix: 'process.env.'})\n : getStudioEnvironmentVariables({jsonEncode: true, prefix: 'process.env.'})\n }\n\n buildDebug('Resolving vite config')\n let viteConfig = await getViteConfig({\n autoUpdates,\n basePath,\n cwd,\n entries,\n getEnvironmentVariables,\n isApp,\n isWorkbenchApp,\n minify,\n mode,\n outputDir,\n reactCompiler,\n schemaExtraction,\n sourceMap,\n })\n\n if (extendViteConfig) {\n const defaultViteConfig = viteConfig\n viteConfig = await extendViteConfigWithUserConfig(\n {command: 'build', mode},\n viteConfig,\n extendViteConfig,\n )\n viteConfig = await finalizeViteConfig(viteConfig, defaultViteConfig)\n }\n\n const fromPath = path.join(cwd, 'static')\n // Copy files placed in /static to the built /static\n buildDebug(`Copying static files from ${fromPath} to output dir`)\n const staticPath = path.join(outputDir, 'static')\n await copyDir(fromPath, staticPath)\n\n // Write favicons, not overwriting ones that already exist, to static folder\n buildDebug('Writing favicons to output dir')\n const faviconBasePath = `${basePath.replace(/\\/+$/, '')}/static`\n await writeFavicons(faviconBasePath, staticPath)\n\n buildDebug('Bundling using vite')\n const bundle = await build(viteConfig)\n buildDebug('Bundling complete')\n\n // For typescript only - this shouldn't ever be the case given we're not watching\n if (Array.isArray(bundle) || !('output' in bundle)) {\n return {chunks: []}\n }\n\n const stats: ChunkStats[] = []\n for (const chunk of bundle.output) {\n if (chunk.type !== 'chunk') {\n continue\n }\n\n stats.push({\n modules: Object.entries(chunk.modules).map(([rawFilePath, chunkModule]) => {\n const filePath = rawFilePath.startsWith('\\u0000')\n ? rawFilePath.slice('\\u0000'.length)\n : rawFilePath\n\n return {\n name: path.isAbsolute(filePath) ? path.relative(cwd, filePath) : filePath,\n renderedLength: chunkModule.renderedLength,\n }\n }),\n name: chunk.name,\n })\n }\n\n return {chunks: stats}\n}\n"],"names":["path","build","createBuilder","copyDir","buildDebug","getAppEnvironmentVariables","getStudioEnvironmentVariables","extendViteConfigWithUserConfig","finalizeViteConfig","getViteConfig","writeFavicons","resolveEntries","writeSanityRuntime","buildStaticFiles","options","appTitle","autoUpdates","basePath","cwd","entry","exposes","isApp","isWorkbenchApp","minify","outputDir","reactCompiler","schemaExtraction","sourceMap","vite","extendViteConfig","workbenchAppId","mode","entries","viteConfig","getEnvironmentVariables","command","builder","buildApp","chunks","reactStrictMode","watch","jsonEncode","prefix","defaultViteConfig","fromPath","join","staticPath","faviconBasePath","replace","bundle","Array","isArray","stats","chunk","output","type","push","modules","Object","map","rawFilePath","chunkModule","filePath","startsWith","slice","length","name","isAbsolute","relative","renderedLength"],"mappings":"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"}
@@ -0,0 +1,220 @@
1
+ import { rm } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { styleText } from 'node:util';
4
+ import { getCliTelemetry, getLocalPackageVersion, getTimer, isInteractive } from '@sanity/cli-core';
5
+ import { confirm, logSymbols, select, spinner } from '@sanity/cli-core/ux';
6
+ import { parse as semverParse } from 'semver';
7
+ import { StudioBuildTrace } from '../../telemetry/build.telemetry.js';
8
+ import { formatModuleSizes, sortModulesBySize } from '../../util/moduleFormatUtils.js';
9
+ import { buildDebug } from './buildDebug.js';
10
+ import { buildStaticFiles } from './buildStaticFiles.js';
11
+ import { checkRequiredDependencies } from './checkRequiredDependencies.js';
12
+ import { checkStudioDependencyVersions } from './checkStudioDependencyVersions.js';
13
+ import { getAutoUpdatesCssUrls, getAutoUpdatesImportMap } from './getAutoUpdatesImportMap.js';
14
+ import { getStudioEnvironmentVariables } from './getEnvironmentVariables.js';
15
+ import { handlePrereleaseVersions } from './handlePrereleaseVersions.js';
16
+ import { resolveVendorBuildConfig } from './resolveVendorBuildConfig.js';
17
+ /**
18
+ * Internal build studio that avoids depending on flags for CLI config.
19
+ * @param options - options for the build
20
+ */ export async function buildStudio(options) {
21
+ buildDebug(`Building studio`);
22
+ const timer = getTimer();
23
+ const { appId, determineBasePath, exposes, isApp, minify, outDir, output, reactCompiler, schemaExtraction, sourceMap, stats, unattendedMode, upgradePackages, vite, workDir } = options;
24
+ const defaultOutputDir = path.resolve(path.join(workDir, 'dist'));
25
+ const outputDir = path.resolve(outDir || defaultOutputDir);
26
+ await checkStudioDependencyVersions(workDir, output);
27
+ // If the check resulted in a dependency install, the CLI command will be re-run,
28
+ // thus we want to exit early
29
+ const { installedSanityVersion } = await checkRequiredDependencies({
30
+ isApp,
31
+ output,
32
+ workDir
33
+ });
34
+ let autoUpdatesEnabled = options.autoUpdatesEnabled;
35
+ let autoUpdatesImports = {};
36
+ let autoUpdatesCssUrls = [];
37
+ if (autoUpdatesEnabled) {
38
+ // Get the clean version without build metadata: https://semver.org/#spec-item-10
39
+ const cleanSanityVersion = semverParse(installedSanityVersion)?.version;
40
+ if (!cleanSanityVersion) {
41
+ throw new Error(`Failed to parse installed Sanity version: ${installedSanityVersion}`);
42
+ }
43
+ output.log(`${logSymbols.info} Building with auto-updates enabled`);
44
+ // Warn if auto updates enabled but no appId configured
45
+ options.checkAppId();
46
+ const installedVisionVersion = await getLocalPackageVersion('@sanity/vision', workDir);
47
+ const cleanVisionVersion = installedVisionVersion ? semverParse(installedVisionVersion)?.version : undefined;
48
+ const sanityDependencies = [
49
+ {
50
+ cssFile: 'index.css',
51
+ name: 'sanity',
52
+ version: cleanSanityVersion
53
+ },
54
+ ...cleanVisionVersion ? [
55
+ {
56
+ cssFile: 'index.css',
57
+ name: '@sanity/vision',
58
+ version: cleanVisionVersion
59
+ }
60
+ ] : [
61
+ {
62
+ name: '@sanity/vision',
63
+ version: cleanSanityVersion
64
+ }
65
+ ]
66
+ ];
67
+ autoUpdatesImports = getAutoUpdatesImportMap(sanityDependencies, {
68
+ appId
69
+ });
70
+ autoUpdatesCssUrls = getAutoUpdatesCssUrls(sanityDependencies, {
71
+ appId
72
+ });
73
+ // Check the versions
74
+ const { mismatched, unresolvedPrerelease } = await options.compareDependencyVersions(sanityDependencies);
75
+ if (unresolvedPrerelease.length > 0) {
76
+ await handlePrereleaseVersions({
77
+ output,
78
+ unattendedMode,
79
+ unresolvedPrerelease
80
+ });
81
+ autoUpdatesImports = {};
82
+ autoUpdatesCssUrls = [];
83
+ autoUpdatesEnabled = false;
84
+ }
85
+ if (mismatched.length > 0 && autoUpdatesEnabled) {
86
+ const versionMismatchWarning = `The following local package versions are different from the versions currently served at runtime.\n` + `When using auto updates, we recommend that you test locally with the same versions before deploying. \n\n` + `${mismatched.map((mod)=>` - ${mod.pkg} (local version: ${mod.installed}, runtime version: ${mod.remote})`).join('\n')}`;
87
+ // If it is non-interactive or in unattended mode, we don't want to prompt
88
+ if (isInteractive() && !unattendedMode) {
89
+ const choice = await select({
90
+ choices: [
91
+ {
92
+ name: `Upgrade local versions (recommended). You will need to run the build command again`,
93
+ value: 'upgrade'
94
+ },
95
+ {
96
+ name: `Upgrade and proceed with build`,
97
+ value: 'upgrade-and-proceed'
98
+ },
99
+ {
100
+ name: `Continue anyway`,
101
+ value: 'continue'
102
+ },
103
+ {
104
+ name: 'Cancel',
105
+ value: 'cancel'
106
+ }
107
+ ],
108
+ default: 'upgrade',
109
+ message: styleText('yellow', `${logSymbols.warning} ${versionMismatchWarning}\n\nDo you want to upgrade local versions before deploying?`)
110
+ });
111
+ if (choice === 'cancel') {
112
+ output.error('Declined to continue with build', {
113
+ exit: 1
114
+ });
115
+ return;
116
+ }
117
+ if (choice === 'upgrade' || choice === 'upgrade-and-proceed') {
118
+ await upgradePackages({
119
+ packages: mismatched.map((res)=>[
120
+ res.pkg,
121
+ res.remote
122
+ ])
123
+ });
124
+ if (choice === 'upgrade') {
125
+ return;
126
+ }
127
+ }
128
+ } else {
129
+ // if non-interactive or unattended, just show the warning
130
+ output.warn(versionMismatchWarning);
131
+ }
132
+ }
133
+ }
134
+ const envVarKeys = Object.keys(getStudioEnvironmentVariables());
135
+ if (envVarKeys.length > 0) {
136
+ output.log('\nIncluding the following environment variables as part of the JavaScript bundle:');
137
+ for (const key of envVarKeys){
138
+ output.log(`- ${key}`);
139
+ }
140
+ output.log('');
141
+ }
142
+ let shouldClean = true;
143
+ if (outputDir !== defaultOutputDir && !unattendedMode && isInteractive()) {
144
+ shouldClean = await confirm({
145
+ default: true,
146
+ message: `Do you want to delete the existing directory (${outputDir}) first?`
147
+ });
148
+ }
149
+ // Determine base path for built studio
150
+ const basePath = determineBasePath();
151
+ if (schemaExtraction?.enabled) {
152
+ output.log(`${logSymbols.info} Building with schema extraction enabled`);
153
+ }
154
+ let spin;
155
+ if (shouldClean) {
156
+ timer.start('cleanOutputFolder');
157
+ spin = spinner('Clean output folder').start();
158
+ await rm(outputDir, {
159
+ force: true,
160
+ recursive: true
161
+ });
162
+ const cleanDuration = timer.end('cleanOutputFolder');
163
+ spin.text = `Clean output folder (${cleanDuration.toFixed(0)}ms)`;
164
+ spin.succeed();
165
+ }
166
+ spin = spinner(`Build Sanity Studio`).start();
167
+ const trace = getCliTelemetry().trace(StudioBuildTrace);
168
+ trace.start();
169
+ let autoUpdates;
170
+ if (autoUpdatesEnabled && !options.isWorkbenchApp) {
171
+ autoUpdates = {
172
+ cssUrls: autoUpdatesCssUrls,
173
+ imports: autoUpdatesImports,
174
+ vendor: await resolveVendorBuildConfig({
175
+ cwd: workDir,
176
+ isApp: false
177
+ })
178
+ };
179
+ }
180
+ try {
181
+ timer.start('bundleStudio');
182
+ const bundle = await buildStaticFiles({
183
+ autoUpdates,
184
+ basePath,
185
+ cwd: workDir,
186
+ exposes,
187
+ isWorkbenchApp: options.isWorkbenchApp,
188
+ minify,
189
+ outputDir,
190
+ reactCompiler,
191
+ schemaExtraction,
192
+ sourceMap,
193
+ vite,
194
+ workbenchAppId: options.workbenchAppId
195
+ });
196
+ trace.log({
197
+ outputSize: bundle.chunks.flatMap((chunk)=>chunk.modules.flatMap((mod)=>mod.renderedLength)).reduce((sum, n)=>sum + n, 0)
198
+ });
199
+ const buildDuration = timer.end('bundleStudio');
200
+ spin.text = `Build Sanity Studio (${buildDuration.toFixed(0)}ms)`;
201
+ spin.succeed();
202
+ trace.complete();
203
+ if (stats) {
204
+ output.log('\nLargest module files:');
205
+ output.log(formatModuleSizes(sortModulesBySize(bundle.chunks).slice(0, 15)));
206
+ }
207
+ } catch (error) {
208
+ spin.fail();
209
+ trace.error(error);
210
+ const message = error instanceof Error ? error.message : String(error);
211
+ buildDebug(`Failed to build Sanity Studio`, {
212
+ error
213
+ });
214
+ output.error(`Failed to build Sanity Studio: ${message}`, {
215
+ exit: 1
216
+ });
217
+ }
218
+ }
219
+
220
+ //# sourceMappingURL=buildStudio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/actions/build/buildStudio.ts"],"sourcesContent":["import {rm} from 'node:fs/promises'\nimport path from 'node:path'\nimport {styleText} from 'node:util'\n\nimport {\n type CliConfig,\n getCliTelemetry,\n getLocalPackageVersion,\n getTimer,\n isInteractive,\n type Output,\n type UserViteConfig,\n} from '@sanity/cli-core'\nimport {confirm, logSymbols, select, spinner, type SpinnerInstance} from '@sanity/cli-core/ux'\nimport {type WorkbenchExposes} from '@sanity/workbench-cli/build'\nimport {parse as semverParse} from 'semver'\n\nimport {StudioBuildTrace} from '../../telemetry/build.telemetry.js'\nimport {CompareDependencyVersionsResult} from '../../util/compareDependencyVersions.js'\nimport {formatModuleSizes, sortModulesBySize} from '../../util/moduleFormatUtils.js'\nimport {buildDebug} from './buildDebug.js'\nimport {buildStaticFiles} from './buildStaticFiles.js'\nimport {checkRequiredDependencies} from './checkRequiredDependencies.js'\nimport {checkStudioDependencyVersions} from './checkStudioDependencyVersions.js'\nimport {getAutoUpdatesCssUrls, getAutoUpdatesImportMap} from './getAutoUpdatesImportMap.js'\nimport {getStudioEnvironmentVariables} from './getEnvironmentVariables.js'\nimport {handlePrereleaseVersions} from './handlePrereleaseVersions.js'\nimport {resolveVendorBuildConfig} from './resolveVendorBuildConfig.js'\n\nexport interface BuildOptions {\n appId: string | undefined\n autoUpdatesEnabled: boolean\n checkAppId: () => void\n compareDependencyVersions: (\n packages: {name: string; version: string}[],\n ) => Promise<CompareDependencyVersionsResult>\n determineBasePath: () => string\n isApp: boolean\n isWorkbenchApp: boolean\n minify: boolean\n outDir: string | undefined\n output: Output\n reactCompiler: CliConfig['reactCompiler']\n schemaExtraction: CliConfig['schemaExtraction']\n sourceMap: boolean\n stats: boolean\n unattendedMode: boolean\n upgradePackages(options: {packages: [name: string, version: string][]}): Promise<void>\n vite: UserViteConfig | undefined\n workDir: string\n\n exposes?: WorkbenchExposes\n\n /** The workbench app's bus identity (`__SANITY_APP_ID__`). */\n workbenchAppId?: string\n}\n\n/**\n * Internal build studio that avoids depending on flags for CLI config.\n * @param options - options for the build\n */\nexport async function buildStudio(options: BuildOptions): Promise<void> {\n buildDebug(`Building studio`)\n\n const timer = getTimer()\n const {\n appId,\n determineBasePath,\n exposes,\n isApp,\n minify,\n outDir,\n output,\n reactCompiler,\n schemaExtraction,\n sourceMap,\n stats,\n unattendedMode,\n upgradePackages,\n vite,\n workDir,\n } = options\n const defaultOutputDir = path.resolve(path.join(workDir, 'dist'))\n const outputDir = path.resolve(outDir || defaultOutputDir)\n\n await checkStudioDependencyVersions(workDir, output)\n\n // If the check resulted in a dependency install, the CLI command will be re-run,\n // thus we want to exit early\n const {installedSanityVersion} = await checkRequiredDependencies({\n isApp,\n output,\n workDir,\n })\n\n let autoUpdatesEnabled = options.autoUpdatesEnabled\n\n let autoUpdatesImports = {}\n let autoUpdatesCssUrls: string[] = []\n\n if (autoUpdatesEnabled) {\n // Get the clean version without build metadata: https://semver.org/#spec-item-10\n const cleanSanityVersion = semverParse(installedSanityVersion)?.version\n if (!cleanSanityVersion) {\n throw new Error(`Failed to parse installed Sanity version: ${installedSanityVersion}`)\n }\n\n output.log(`${logSymbols.info} Building with auto-updates enabled`)\n\n // Warn if auto updates enabled but no appId configured\n options.checkAppId()\n\n const installedVisionVersion = await getLocalPackageVersion('@sanity/vision', workDir)\n const cleanVisionVersion = installedVisionVersion\n ? semverParse(installedVisionVersion)?.version\n : undefined\n\n const sanityDependencies = [\n {cssFile: 'index.css', name: 'sanity', version: cleanSanityVersion},\n ...(cleanVisionVersion\n ? [{cssFile: 'index.css', name: '@sanity/vision' as const, version: cleanVisionVersion}]\n : [{name: '@sanity/vision' as const, version: cleanSanityVersion}]),\n ]\n autoUpdatesImports = getAutoUpdatesImportMap(sanityDependencies, {appId})\n\n autoUpdatesCssUrls = getAutoUpdatesCssUrls(sanityDependencies, {appId})\n\n // Check the versions\n const {mismatched, unresolvedPrerelease} =\n await options.compareDependencyVersions(sanityDependencies)\n\n if (unresolvedPrerelease.length > 0) {\n await handlePrereleaseVersions({output, unattendedMode, unresolvedPrerelease})\n autoUpdatesImports = {}\n autoUpdatesCssUrls = []\n autoUpdatesEnabled = false\n }\n\n if (mismatched.length > 0 && autoUpdatesEnabled) {\n const versionMismatchWarning =\n `The following local package versions are different from the versions currently served at runtime.\\n` +\n `When using auto updates, we recommend that you test locally with the same versions before deploying. \\n\\n` +\n `${mismatched.map((mod) => ` - ${mod.pkg} (local version: ${mod.installed}, runtime version: ${mod.remote})`).join('\\n')}`\n\n // If it is non-interactive or in unattended mode, we don't want to prompt\n if (isInteractive() && !unattendedMode) {\n const choice = await select({\n choices: [\n {\n name: `Upgrade local versions (recommended). You will need to run the build command again`,\n value: 'upgrade',\n },\n {\n name: `Upgrade and proceed with build`,\n value: 'upgrade-and-proceed',\n },\n {\n name: `Continue anyway`,\n value: 'continue',\n },\n {name: 'Cancel', value: 'cancel'},\n ],\n default: 'upgrade',\n message: styleText(\n 'yellow',\n `${logSymbols.warning} ${versionMismatchWarning}\\n\\nDo you want to upgrade local versions before deploying?`,\n ),\n })\n\n if (choice === 'cancel') {\n output.error('Declined to continue with build', {exit: 1})\n return\n }\n\n if (choice === 'upgrade' || choice === 'upgrade-and-proceed') {\n await upgradePackages({\n packages: mismatched.map((res) => [res.pkg, res.remote]),\n })\n\n if (choice === 'upgrade') {\n return\n }\n }\n } else {\n // if non-interactive or unattended, just show the warning\n output.warn(versionMismatchWarning)\n }\n }\n }\n\n const envVarKeys = Object.keys(getStudioEnvironmentVariables())\n if (envVarKeys.length > 0) {\n output.log('\\nIncluding the following environment variables as part of the JavaScript bundle:')\n for (const key of envVarKeys) {\n output.log(`- ${key}`)\n }\n output.log('')\n }\n\n let shouldClean = true\n if (outputDir !== defaultOutputDir && !unattendedMode && isInteractive()) {\n shouldClean = await confirm({\n default: true,\n message: `Do you want to delete the existing directory (${outputDir}) first?`,\n })\n }\n\n // Determine base path for built studio\n const basePath = determineBasePath()\n\n if (schemaExtraction?.enabled) {\n output.log(`${logSymbols.info} Building with schema extraction enabled`)\n }\n\n let spin: SpinnerInstance\n if (shouldClean) {\n timer.start('cleanOutputFolder')\n spin = spinner('Clean output folder').start()\n await rm(outputDir, {force: true, recursive: true})\n const cleanDuration = timer.end('cleanOutputFolder')\n spin.text = `Clean output folder (${cleanDuration.toFixed(0)}ms)`\n spin.succeed()\n }\n\n spin = spinner(`Build Sanity Studio`).start()\n\n const trace = getCliTelemetry().trace(StudioBuildTrace)\n trace.start()\n\n let autoUpdates\n if (autoUpdatesEnabled && !options.isWorkbenchApp) {\n autoUpdates = {\n cssUrls: autoUpdatesCssUrls,\n imports: autoUpdatesImports,\n vendor: await resolveVendorBuildConfig({cwd: workDir, isApp: false}),\n }\n }\n\n try {\n timer.start('bundleStudio')\n\n const bundle = await buildStaticFiles({\n autoUpdates,\n basePath,\n cwd: workDir,\n exposes,\n isWorkbenchApp: options.isWorkbenchApp,\n minify,\n outputDir,\n reactCompiler,\n schemaExtraction,\n sourceMap,\n vite,\n workbenchAppId: options.workbenchAppId,\n })\n\n trace.log({\n outputSize: bundle.chunks\n .flatMap((chunk) => chunk.modules.flatMap((mod) => mod.renderedLength))\n .reduce((sum, n) => sum + n, 0),\n })\n const buildDuration = timer.end('bundleStudio')\n\n spin.text = `Build Sanity Studio (${buildDuration.toFixed(0)}ms)`\n spin.succeed()\n\n trace.complete()\n if (stats) {\n output.log('\\nLargest module files:')\n output.log(formatModuleSizes(sortModulesBySize(bundle.chunks).slice(0, 15)))\n }\n } catch (error) {\n spin.fail()\n trace.error(error)\n const message = error instanceof Error ? error.message : String(error)\n buildDebug(`Failed to build Sanity Studio`, {error})\n output.error(`Failed to build Sanity Studio: ${message}`, {exit: 1})\n }\n}\n"],"names":["rm","path","styleText","getCliTelemetry","getLocalPackageVersion","getTimer","isInteractive","confirm","logSymbols","select","spinner","parse","semverParse","StudioBuildTrace","formatModuleSizes","sortModulesBySize","buildDebug","buildStaticFiles","checkRequiredDependencies","checkStudioDependencyVersions","getAutoUpdatesCssUrls","getAutoUpdatesImportMap","getStudioEnvironmentVariables","handlePrereleaseVersions","resolveVendorBuildConfig","buildStudio","options","timer","appId","determineBasePath","exposes","isApp","minify","outDir","output","reactCompiler","schemaExtraction","sourceMap","stats","unattendedMode","upgradePackages","vite","workDir","defaultOutputDir","resolve","join","outputDir","installedSanityVersion","autoUpdatesEnabled","autoUpdatesImports","autoUpdatesCssUrls","cleanSanityVersion","version","Error","log","info","checkAppId","installedVisionVersion","cleanVisionVersion","undefined","sanityDependencies","cssFile","name","mismatched","unresolvedPrerelease","compareDependencyVersions","length","versionMismatchWarning","map","mod","pkg","installed","remote","choice","choices","value","default","message","warning","error","exit","packages","res","warn","envVarKeys","Object","keys","key","shouldClean","basePath","enabled","spin","start","force","recursive","cleanDuration","end","text","toFixed","succeed","trace","autoUpdates","isWorkbenchApp","cssUrls","imports","vendor","cwd","bundle","workbenchAppId","outputSize","chunks","flatMap","chunk","modules","renderedLength","reduce","sum","n","buildDuration","complete","slice","fail","String"],"mappings":"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"}
@@ -20,8 +20,8 @@ import { getDefaultFaviconsPath } from './writeFavicons.js';
20
20
  *
21
21
  * @internal Only meant for consumption inside of Sanity modules, do not depend on this externally
22
22
  */ export async function getViteConfig(options) {
23
- const { additionalPlugins, autoUpdates, basePath: rawBasePath = '/', cwd, entries, isApp, isWorkbenchApp, minify, mode, outputDir, reactCompiler, schemaExtraction, server, services, // default to `true` when `mode=development`
24
- sourceMap = options.mode === 'development', views } = options;
23
+ const { additionalPlugins, autoUpdates, basePath: rawBasePath = '/', cwd, entries, exposes, isApp, isWorkbenchApp, minify, mode, outputDir, reactCompiler, schemaExtraction, server, // default to `true` when `mode=development`
24
+ sourceMap = options.mode === 'development', workbenchAppId } = options;
25
25
  const basePath = normalizeBasePath(rawBasePath);
26
26
  const configPath = (await findProjectRoot(cwd)).path;
27
27
  const customFaviconsPath = path.join(cwd, 'static');
@@ -84,11 +84,11 @@ import { getDefaultFaviconsPath } from './writeFavicons.js';
84
84
  ...isWorkbenchApp ? [
85
85
  ...sharedPlugins,
86
86
  await workbenchVitePlugins({
87
+ appId: workbenchAppId,
87
88
  cwd,
88
89
  entries,
89
- isApp,
90
- services,
91
- views
90
+ exposes,
91
+ isApp
92
92
  })
93
93
  ] : [
94
94
  ...sharedPlugins,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/build/getViteConfig.ts"],"sourcesContent":["import path from 'node:path'\n\nimport babel from '@rolldown/plugin-babel'\nimport {\n type CliConfig,\n findProjectRoot,\n getCliTelemetry,\n type UserViteConfig,\n} from '@sanity/cli-core'\nimport {type DefineAppInput} from '@sanity/workbench-cli'\nimport {workbenchVitePlugins} from '@sanity/workbench-cli/build'\nimport viteReact, {reactCompilerPreset} from '@vitejs/plugin-react'\nimport {type PluginOptions as ReactCompilerConfig} from 'babel-plugin-react-compiler'\nimport debug from 'debug'\nimport {\n type ConfigEnv,\n esmExternalRequirePlugin,\n type InlineConfig,\n mergeConfig,\n type Plugin,\n type PluginOption,\n type Rolldown,\n} from 'vite'\n\nimport {SANITY_CACHE_DIR} from '../../constants.js'\nimport {sanitySchemaExtractionPlugin} from '../schema/vite/plugin-schema-extraction.js'\nimport {type AutoUpdatesBuildConfig} from './autoUpdates.js'\nimport {VENDOR_DIR} from './constants.js'\nimport {createExternalFromImportMap} from './createExternalFromImportMap.js'\nimport {normalizeBasePath} from './normalizeBasePath.js'\nimport {sanityBuildEntries} from './vite/plugin-sanity-build-entries.js'\nimport {sanityFaviconsPlugin} from './vite/plugin-sanity-favicons.js'\nimport {sanityRuntimeRewritePlugin} from './vite/plugin-sanity-runtime-rewrite.js'\nimport {createVendorNamedExportsPlugin} from './vite/plugin-sanity-vendor-named-exports.js'\nimport {getDefaultFaviconsPath} from './writeFavicons.js'\n\ninterface ViteOptions {\n /**\n * Root path of the studio/sanity app\n */\n cwd: string\n\n entries: {\n relativeConfigLocation: string | null\n // `null` when a branded app declares no `entry` (sanity-io/workbench spec 002-workbench-extension-api, US5) — no app view.\n relativeEntry: string | null\n }\n\n /**\n * Returns the environment variables to be injected into the config.\n */\n getEnvironmentVariables(): Record<string, string>\n\n /**\n * Mode to run vite in - eg development or production\n */\n mode: 'development' | 'production'\n\n reactCompiler: ReactCompilerConfig | undefined\n\n /**\n * Additional plugins when configured, eg. typegen\n */\n additionalPlugins?: Plugin[]\n\n /**\n * Auto-updates configuration (production builds only). When set, vendor\n * packages are emitted as hashed ESM chunks by this build and the import map\n * in `index.html` is derived from the build output.\n */\n autoUpdates?: AutoUpdatesBuildConfig\n\n /**\n * Base path (eg under where to serve the app - `/studio` or similar)\n * Will be normalized to ensure it starts and ends with a `/`\n */\n basePath?: string\n\n isApp?: boolean\n\n /**\n * Whether this is a workbench app (opted in via `unstable_defineApp`). Drives\n * the module-federation build.\n */\n isWorkbenchApp?: boolean\n\n /**\n * Whether or not to minify the output (only used in `mode: 'production'`)\n */\n minify?: boolean\n\n /**\n * Output directory (eg where to place the built files, if any)\n */\n outputDir?: string\n\n /**\n * Schema extraction configuration\n */\n schemaExtraction?: CliConfig['schemaExtraction']\n\n /**\n * HTTP development server configuration\n */\n server?: {host?: string; port?: number}\n /**\n * Background services the workbench app declares. Built into self-contained\n * worker bundles and exposed through module federation as `./services/<name>`.\n */\n services?: DefineAppInput['services']\n\n /**\n * Whether or not to enable source maps\n */\n sourceMap?: boolean\n\n /**\n * Views the workbench app declares. Built into render-contract artifacts and\n * exposed through module federation as `./views/<name>`.\n */\n views?: DefineAppInput['views']\n}\n\n/**\n * Get a configuration object for Vite based on the passed options\n *\n * @internal Only meant for consumption inside of Sanity modules, do not depend on this externally\n */\nexport async function getViteConfig(options: ViteOptions): Promise<InlineConfig> {\n const {\n additionalPlugins,\n autoUpdates,\n basePath: rawBasePath = '/',\n cwd,\n entries,\n isApp,\n isWorkbenchApp,\n minify,\n mode,\n outputDir,\n reactCompiler,\n schemaExtraction,\n server,\n services,\n // default to `true` when `mode=development`\n sourceMap = options.mode === 'development',\n views,\n } = options\n\n const basePath = normalizeBasePath(rawBasePath)\n\n const configPath = (await findProjectRoot(cwd)).path\n\n const customFaviconsPath = path.join(cwd, 'static')\n const defaultFaviconsPath = await getDefaultFaviconsPath()\n const staticPath = `${basePath}static`\n\n const envVars = options.getEnvironmentVariables()\n\n const sharedPlugins: PluginOption = [\n viteReact(),\n ...(reactCompiler ? [babel({presets: [reactCompilerPreset(reactCompiler)]})] : []),\n ...(schemaExtraction?.enabled\n ? [\n sanitySchemaExtractionPlugin({\n additionalPatterns: schemaExtraction.watchPatterns,\n configPath,\n enforceRequiredFields: schemaExtraction.enforceRequiredFields,\n outputPath: schemaExtraction.path,\n telemetryLogger: getCliTelemetry(),\n workDir: cwd,\n workspaceName: schemaExtraction.workspace,\n }),\n ]\n : []),\n ]\n\n const viteConfig: InlineConfig = {\n base: basePath,\n build: {\n outDir: outputDir || path.resolve(cwd, 'dist'),\n sourcemap: sourceMap,\n },\n // Define a custom cache directory so that sanity's vite cache\n // does not conflict with any potential local vite projects\n cacheDir: `${SANITY_CACHE_DIR}/vite`,\n configFile: false,\n define: {\n __SANITY_BUILD_TIMESTAMP__: JSON.stringify(Date.now()),\n __SANITY_STAGING__: process.env.SANITY_INTERNAL_ENV === 'staging',\n 'process.env.MODE': JSON.stringify(mode),\n 'process.env.PKG_BUILD_VERSION': JSON.stringify(process.env.PKG_BUILD_VERSION),\n /**\n * Yes, double negatives are confusing.\n * The default value of `SC_DISABLE_SPEEDY` is `process.env.NODE_ENV === 'production'`: https://github.com/styled-components/styled-components/blob/99c02f52d69e8e509c0bf012cadee7f8e819a6dd/packages/styled-components/src/constants.ts#L34\n * Which means that in production, use the much faster way of inserting CSS rules, based on the CSSStyleSheet API (https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/insertRule)\n * while in dev mode, use the slower way of inserting CSS rules, which appends text nodes to the `<style>` tag: https://github.com/styled-components/styled-components/blob/99c02f52d69e8e509c0bf012cadee7f8e819a6dd/packages/styled-components/src/sheet/Tag.ts#L74-L76\n * There are historical reasons for this, primarily that browsers initially did not support editing CSS rules in the DevTools inspector if `CSSStyleSheet.insetRule` were used.\n * However, that's no longer the case (since Chrome 81 back in April 2020: https://developer.chrome.com/docs/css-ui/css-in-js), the latest version of FireFox also supports it,\n * and there is no longer any reason to use the much slower method in dev mode.\n */\n 'process.env.SC_DISABLE_SPEEDY': JSON.stringify('false'),\n ...envVars,\n },\n envPrefix: isApp ? 'SANITY_APP_' : 'SANITY_STUDIO_',\n logLevel: mode === 'production' ? 'silent' : 'info',\n mode,\n plugins: [\n // Federation builds only need the federation plugin — skip client-specific\n // plugins (favicons, runtime rewrite, build entries)\n ...(isWorkbenchApp\n ? [...sharedPlugins, await workbenchVitePlugins({cwd, entries, isApp, services, views})]\n : [\n ...sharedPlugins,\n sanityFaviconsPlugin({\n customFaviconsPath,\n defaultFaviconsPath,\n staticUrlPath: staticPath,\n }),\n sanityRuntimeRewritePlugin(),\n sanityBuildEntries({autoUpdates, basePath, cwd, isApp}),\n ]),\n // Caller-provided plugins (e.g. typegen in dev) aren't client-specific,\n // so they apply to federation builds too.\n ...(additionalPlugins || []),\n ],\n resolve: {\n dedupe: ['react', 'react-dom', 'sanity', 'styled-components'],\n // Honor the studio's tsconfig `paths`, consistent with studioWorkerLoader.worker.ts.\n tsconfigPaths: true,\n },\n root: cwd,\n server: {\n host: server?.host,\n port: server?.port || 3333,\n // Apps drift to a free port (the reported URL embeds whichever port was\n // claimed), and workbench runs stack servers on adjacent ports — both\n // need the fallback. Studios fail fast on a busy port.\n strictPort: !isApp && !isWorkbenchApp,\n\n /**\n * Significantly speed up startup time,\n * and most importantly eliminates the `new dependencies optimized: foobar. optimized dependencies changed. reloading`\n * types of initial reload loops that otherwise happen as vite discovers deps that need to be optimized.\n * This option starts the traversal up front, and warms up the dep tree required to render the userland sanity.config.ts file,\n * and thus avoids frustrating reload loops.\n */\n warmup: {\n clientFiles: ['./.sanity/runtime/app.js'],\n },\n },\n }\n\n // Federation builds don't produce a client bundle — the federation\n // plugin configures its own environment and build entry point.\n if (mode === 'production' && !isWorkbenchApp) {\n if (autoUpdates) {\n viteConfig.plugins!.push(\n // Re-expose CommonJS named exports (react, react-dom) as real ESM exports\n // on the emitted vendor chunks; Rolldown only emits `export default` for a\n // CommonJS entry.\n createVendorNamedExportsPlugin(autoUpdates.vendor.namesByChunkName),\n // The import map and vendor specifiers are externals of the studio/app\n // bundle, resolved by the browser at runtime. They are handed to\n // `esmExternalRequirePlugin` rather than `rolldownOptions.external`: the\n // plugin both marks them external AND rewrites bundled CommonJS\n // `require()` calls of an external (e.g. react-dom requiring react) into\n // ESM imports, while `rolldownOptions.external` would short-circuit that\n // rewrite and leave a runtime `require` shim that throws in the browser.\n esmExternalRequirePlugin({\n external: createExternalFromImportMap({\n imports: {\n ...autoUpdates.imports,\n ...Object.fromEntries(\n Object.values(autoUpdates.vendor.specifiersByChunkName).map((specifier) => [\n specifier,\n '',\n ]),\n ),\n },\n }),\n }),\n )\n }\n\n const vendorChunkNames = autoUpdates\n ? new Set(Object.keys(autoUpdates.vendor.specifiersByChunkName))\n : null\n\n viteConfig.build = {\n ...viteConfig.build,\n\n assetsDir: 'static',\n emptyOutDir: false, // Rely on CLI to do this\n minify: minify ? 'oxc' : false,\n\n rolldownOptions: {\n input: {\n sanity: path.join(cwd, '.sanity', 'runtime', 'app.js'),\n ...autoUpdates?.vendor.entries,\n },\n onwarn: onRolldownWarn,\n ...(autoUpdates\n ? {\n // Expose Rolldown's native MagicString on `renderChunk`'s `meta` so\n // the vendor named-exports plugin can edit chunks without a JS\n // dependency.\n experimental: {nativeMagicString: true},\n output: {\n entryFileNames: (chunk) =>\n vendorChunkNames!.has(chunk.name)\n ? `${VENDOR_DIR}/[name]-[hash].mjs`\n : 'static/[name]-[hash].js',\n exports: 'named',\n },\n // App-style builds default to `preserveEntrySignatures: false`, which\n // treeshakes the exports off entry chunks. Vendor chunks are loaded by\n // the browser via the import map, so their exports must survive (e.g.\n // styled-components' native ESM exports). `exports-only` keeps exports\n // for entries that have them, while the export-less `sanity` app entry\n // still bundles as before.\n preserveEntrySignatures: 'exports-only',\n }\n : {}),\n },\n }\n }\n\n return viteConfig\n}\n\nfunction onRolldownWarn(warning: Rolldown.RolldownLog, warn: Rolldown.LoggingFunction) {\n if (suppressUnusedImport(warning)) {\n return\n }\n\n warn(warning)\n}\n\nfunction suppressUnusedImport(warning: Rolldown.RolldownLog & {ids?: string[]}): boolean {\n if (warning.code !== 'UNUSED_EXTERNAL_IMPORT') return false\n\n // Suppress:\n // ```\n // \"useDebugValue\" is imported from external module \"react\"…\n // ```\n if (warning.names?.includes('useDebugValue')) {\n warning.names = warning.names.filter((n) => n !== 'useDebugValue')\n if (warning.names.length === 0) return true\n }\n\n // If some library does something unexpected, we suppress since it isn't actionable\n if (warning.ids?.every((id) => id.includes('/node_modules/') || id.includes('\\\\node_modules\\\\')))\n return true\n\n return false\n}\n\n/**\n * Re-asserts the critical parts of the default config after a userland vite\n * config (`vite` in `sanity.cli.ts`) has been applied.\n *\n * Everything `getViteConfig` sets under `build.rolldownOptions` is load-bearing:\n * the `input` entries (the studio entry plus, for auto-updating studios/apps,\n * the vendor entries), `preserveEntrySignatures`, the `experimental` flags the\n * vendor plugins rely on, and the `output` chunk naming. A userland config that\n * returns a brand-new object for any of these would silently break the build\n * (e.g. vendor chunks never emitted while the bundle still treats them as\n * external), so the default `rolldownOptions` are deep-merged back over the\n * userland config: userland additions survive, replacements of critical\n * options are healed.\n *\n * @param config - User-modified configuration\n * @param defaultConfig - The configuration produced by `getViteConfig`, before the userland config was applied\n * @returns Merged configuration\n * @internal\n */\nexport async function finalizeViteConfig(\n config: InlineConfig,\n defaultConfig: InlineConfig,\n): Promise<InlineConfig> {\n if (typeof config.build?.rolldownOptions?.input !== 'object') {\n throw new TypeError(\n 'Vite config must contain `build.rolldownOptions.input`, and it must be an object',\n )\n }\n\n if (!config.root) {\n throw new Error(\n 'Vite config must contain `root` property, and must point to the Sanity root directory',\n )\n }\n\n return mergeConfig(config, {\n build: {\n rolldownOptions: defaultConfig.build?.rolldownOptions ?? {},\n },\n })\n}\n\n/**\n * Merge user-provided Vite configuration object or function\n *\n * @param defaultConfig - Default configuration object\n * @param userConfig - User-provided configuration object or function\n * @returns Merged configuration\n * @internal\n */\nexport async function extendViteConfigWithUserConfig(\n env: ConfigEnv,\n defaultConfig: InlineConfig,\n userConfig: UserViteConfig,\n): Promise<InlineConfig> {\n let config = defaultConfig\n\n if (typeof userConfig === 'function') {\n debug('Extending vite config using user-specified function')\n config = await userConfig(config, env)\n } else if (typeof userConfig === 'object') {\n debug('Merging vite config using user-specified object')\n config = mergeConfig(config, userConfig)\n }\n\n return config\n}\n"],"names":["path","babel","findProjectRoot","getCliTelemetry","workbenchVitePlugins","viteReact","reactCompilerPreset","debug","esmExternalRequirePlugin","mergeConfig","SANITY_CACHE_DIR","sanitySchemaExtractionPlugin","VENDOR_DIR","createExternalFromImportMap","normalizeBasePath","sanityBuildEntries","sanityFaviconsPlugin","sanityRuntimeRewritePlugin","createVendorNamedExportsPlugin","getDefaultFaviconsPath","getViteConfig","options","additionalPlugins","autoUpdates","basePath","rawBasePath","cwd","entries","isApp","isWorkbenchApp","minify","mode","outputDir","reactCompiler","schemaExtraction","server","services","sourceMap","views","configPath","customFaviconsPath","join","defaultFaviconsPath","staticPath","envVars","getEnvironmentVariables","sharedPlugins","presets","enabled","additionalPatterns","watchPatterns","enforceRequiredFields","outputPath","telemetryLogger","workDir","workspaceName","workspace","viteConfig","base","build","outDir","resolve","sourcemap","cacheDir","configFile","define","__SANITY_BUILD_TIMESTAMP__","JSON","stringify","Date","now","__SANITY_STAGING__","process","env","SANITY_INTERNAL_ENV","PKG_BUILD_VERSION","envPrefix","logLevel","plugins","staticUrlPath","dedupe","tsconfigPaths","root","host","port","strictPort","warmup","clientFiles","push","vendor","namesByChunkName","external","imports","Object","fromEntries","values","specifiersByChunkName","map","specifier","vendorChunkNames","Set","keys","assetsDir","emptyOutDir","rolldownOptions","input","sanity","onwarn","onRolldownWarn","experimental","nativeMagicString","output","entryFileNames","chunk","has","name","exports","preserveEntrySignatures","warning","warn","suppressUnusedImport","code","names","includes","filter","n","length","ids","every","id","finalizeViteConfig","config","defaultConfig","TypeError","Error","extendViteConfigWithUserConfig","userConfig"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/actions/build/getViteConfig.ts"],"sourcesContent":["import path from 'node:path'\n\nimport babel from '@rolldown/plugin-babel'\nimport {\n type CliConfig,\n findProjectRoot,\n getCliTelemetry,\n type UserViteConfig,\n} from '@sanity/cli-core'\nimport {type WorkbenchExposes, workbenchVitePlugins} from '@sanity/workbench-cli/build'\nimport viteReact, {reactCompilerPreset} from '@vitejs/plugin-react'\nimport {type PluginOptions as ReactCompilerConfig} from 'babel-plugin-react-compiler'\nimport debug from 'debug'\nimport {\n type ConfigEnv,\n esmExternalRequirePlugin,\n type InlineConfig,\n mergeConfig,\n type Plugin,\n type PluginOption,\n type Rolldown,\n} from 'vite'\n\nimport {SANITY_CACHE_DIR} from '../../constants.js'\nimport {sanitySchemaExtractionPlugin} from '../schema/vite/plugin-schema-extraction.js'\nimport {type AutoUpdatesBuildConfig} from './autoUpdates.js'\nimport {VENDOR_DIR} from './constants.js'\nimport {createExternalFromImportMap} from './createExternalFromImportMap.js'\nimport {normalizeBasePath} from './normalizeBasePath.js'\nimport {sanityBuildEntries} from './vite/plugin-sanity-build-entries.js'\nimport {sanityFaviconsPlugin} from './vite/plugin-sanity-favicons.js'\nimport {sanityRuntimeRewritePlugin} from './vite/plugin-sanity-runtime-rewrite.js'\nimport {createVendorNamedExportsPlugin} from './vite/plugin-sanity-vendor-named-exports.js'\nimport {getDefaultFaviconsPath} from './writeFavicons.js'\n\ninterface ViteOptions {\n /**\n * Root path of the studio/sanity app\n */\n cwd: string\n\n entries: {\n relativeConfigLocation: string | null\n // `null` when a branded app declares no `entry` (sanity-io/workbench spec 002-workbench-extension-api, US5) — no app view.\n relativeEntry: string | null\n }\n\n /**\n * Returns the environment variables to be injected into the config.\n */\n getEnvironmentVariables(): Record<string, string>\n\n /**\n * Mode to run vite in - eg development or production\n */\n mode: 'development' | 'production'\n\n reactCompiler: ReactCompilerConfig | undefined\n\n /**\n * Additional plugins when configured, eg. typegen\n */\n additionalPlugins?: Plugin[]\n\n /**\n * Auto-updates configuration (production builds only). When set, vendor\n * packages are emitted as hashed ESM chunks by this build and the import map\n * in `index.html` is derived from the build output.\n */\n autoUpdates?: AutoUpdatesBuildConfig\n\n /**\n * Base path (eg under where to serve the app - `/studio` or similar)\n * Will be normalized to ensure it starts and ends with a `/`\n */\n basePath?: string\n\n exposes?: WorkbenchExposes\n\n isApp?: boolean\n\n /**\n * Whether this is a workbench app (opted in via `unstable_defineApp`). Drives\n * the module-federation build.\n */\n isWorkbenchApp?: boolean\n\n /**\n * Whether or not to minify the output (only used in `mode: 'production'`)\n */\n minify?: boolean\n\n /**\n * Output directory (eg where to place the built files, if any)\n */\n outputDir?: string\n\n /**\n * Schema extraction configuration\n */\n schemaExtraction?: CliConfig['schemaExtraction']\n\n /**\n * HTTP development server configuration\n */\n server?: {host?: string; port?: number}\n\n /**\n * Whether or not to enable source maps\n */\n sourceMap?: boolean\n\n /**\n * The workbench app's bus identity, stamped into its modules as\n * `__SANITY_APP_ID__` for `@sanity/runtime`. Only read for workbench apps.\n */\n workbenchAppId?: string\n}\n\n/**\n * Get a configuration object for Vite based on the passed options\n *\n * @internal Only meant for consumption inside of Sanity modules, do not depend on this externally\n */\nexport async function getViteConfig(options: ViteOptions): Promise<InlineConfig> {\n const {\n additionalPlugins,\n autoUpdates,\n basePath: rawBasePath = '/',\n cwd,\n entries,\n exposes,\n isApp,\n isWorkbenchApp,\n minify,\n mode,\n outputDir,\n reactCompiler,\n schemaExtraction,\n server,\n // default to `true` when `mode=development`\n sourceMap = options.mode === 'development',\n workbenchAppId,\n } = options\n\n const basePath = normalizeBasePath(rawBasePath)\n\n const configPath = (await findProjectRoot(cwd)).path\n\n const customFaviconsPath = path.join(cwd, 'static')\n const defaultFaviconsPath = await getDefaultFaviconsPath()\n const staticPath = `${basePath}static`\n\n const envVars = options.getEnvironmentVariables()\n\n const sharedPlugins: PluginOption = [\n viteReact(),\n ...(reactCompiler ? [babel({presets: [reactCompilerPreset(reactCompiler)]})] : []),\n ...(schemaExtraction?.enabled\n ? [\n sanitySchemaExtractionPlugin({\n additionalPatterns: schemaExtraction.watchPatterns,\n configPath,\n enforceRequiredFields: schemaExtraction.enforceRequiredFields,\n outputPath: schemaExtraction.path,\n telemetryLogger: getCliTelemetry(),\n workDir: cwd,\n workspaceName: schemaExtraction.workspace,\n }),\n ]\n : []),\n ]\n\n const viteConfig: InlineConfig = {\n base: basePath,\n build: {\n outDir: outputDir || path.resolve(cwd, 'dist'),\n sourcemap: sourceMap,\n },\n // Define a custom cache directory so that sanity's vite cache\n // does not conflict with any potential local vite projects\n cacheDir: `${SANITY_CACHE_DIR}/vite`,\n configFile: false,\n define: {\n __SANITY_BUILD_TIMESTAMP__: JSON.stringify(Date.now()),\n __SANITY_STAGING__: process.env.SANITY_INTERNAL_ENV === 'staging',\n 'process.env.MODE': JSON.stringify(mode),\n 'process.env.PKG_BUILD_VERSION': JSON.stringify(process.env.PKG_BUILD_VERSION),\n /**\n * Yes, double negatives are confusing.\n * The default value of `SC_DISABLE_SPEEDY` is `process.env.NODE_ENV === 'production'`: https://github.com/styled-components/styled-components/blob/99c02f52d69e8e509c0bf012cadee7f8e819a6dd/packages/styled-components/src/constants.ts#L34\n * Which means that in production, use the much faster way of inserting CSS rules, based on the CSSStyleSheet API (https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/insertRule)\n * while in dev mode, use the slower way of inserting CSS rules, which appends text nodes to the `<style>` tag: https://github.com/styled-components/styled-components/blob/99c02f52d69e8e509c0bf012cadee7f8e819a6dd/packages/styled-components/src/sheet/Tag.ts#L74-L76\n * There are historical reasons for this, primarily that browsers initially did not support editing CSS rules in the DevTools inspector if `CSSStyleSheet.insetRule` were used.\n * However, that's no longer the case (since Chrome 81 back in April 2020: https://developer.chrome.com/docs/css-ui/css-in-js), the latest version of FireFox also supports it,\n * and there is no longer any reason to use the much slower method in dev mode.\n */\n 'process.env.SC_DISABLE_SPEEDY': JSON.stringify('false'),\n ...envVars,\n },\n envPrefix: isApp ? 'SANITY_APP_' : 'SANITY_STUDIO_',\n logLevel: mode === 'production' ? 'silent' : 'info',\n mode,\n plugins: [\n // Federation builds only need the federation plugin — skip client-specific\n // plugins (favicons, runtime rewrite, build entries)\n ...(isWorkbenchApp\n ? [\n ...sharedPlugins,\n await workbenchVitePlugins({appId: workbenchAppId, cwd, entries, exposes, isApp}),\n ]\n : [\n ...sharedPlugins,\n sanityFaviconsPlugin({\n customFaviconsPath,\n defaultFaviconsPath,\n staticUrlPath: staticPath,\n }),\n sanityRuntimeRewritePlugin(),\n sanityBuildEntries({autoUpdates, basePath, cwd, isApp}),\n ]),\n // Caller-provided plugins (e.g. typegen in dev) aren't client-specific,\n // so they apply to federation builds too.\n ...(additionalPlugins || []),\n ],\n resolve: {\n dedupe: ['react', 'react-dom', 'sanity', 'styled-components'],\n // Honor the studio's tsconfig `paths`, consistent with studioWorkerLoader.worker.ts.\n tsconfigPaths: true,\n },\n root: cwd,\n server: {\n host: server?.host,\n port: server?.port || 3333,\n // Apps drift to a free port (the reported URL embeds whichever port was\n // claimed), and workbench runs stack servers on adjacent ports — both\n // need the fallback. Studios fail fast on a busy port.\n strictPort: !isApp && !isWorkbenchApp,\n\n /**\n * Significantly speed up startup time,\n * and most importantly eliminates the `new dependencies optimized: foobar. optimized dependencies changed. reloading`\n * types of initial reload loops that otherwise happen as vite discovers deps that need to be optimized.\n * This option starts the traversal up front, and warms up the dep tree required to render the userland sanity.config.ts file,\n * and thus avoids frustrating reload loops.\n */\n warmup: {\n clientFiles: ['./.sanity/runtime/app.js'],\n },\n },\n }\n\n // Federation builds don't produce a client bundle — the federation\n // plugin configures its own environment and build entry point.\n if (mode === 'production' && !isWorkbenchApp) {\n if (autoUpdates) {\n viteConfig.plugins!.push(\n // Re-expose CommonJS named exports (react, react-dom) as real ESM exports\n // on the emitted vendor chunks; Rolldown only emits `export default` for a\n // CommonJS entry.\n createVendorNamedExportsPlugin(autoUpdates.vendor.namesByChunkName),\n // The import map and vendor specifiers are externals of the studio/app\n // bundle, resolved by the browser at runtime. They are handed to\n // `esmExternalRequirePlugin` rather than `rolldownOptions.external`: the\n // plugin both marks them external AND rewrites bundled CommonJS\n // `require()` calls of an external (e.g. react-dom requiring react) into\n // ESM imports, while `rolldownOptions.external` would short-circuit that\n // rewrite and leave a runtime `require` shim that throws in the browser.\n esmExternalRequirePlugin({\n external: createExternalFromImportMap({\n imports: {\n ...autoUpdates.imports,\n ...Object.fromEntries(\n Object.values(autoUpdates.vendor.specifiersByChunkName).map((specifier) => [\n specifier,\n '',\n ]),\n ),\n },\n }),\n }),\n )\n }\n\n const vendorChunkNames = autoUpdates\n ? new Set(Object.keys(autoUpdates.vendor.specifiersByChunkName))\n : null\n\n viteConfig.build = {\n ...viteConfig.build,\n\n assetsDir: 'static',\n emptyOutDir: false, // Rely on CLI to do this\n minify: minify ? 'oxc' : false,\n\n rolldownOptions: {\n input: {\n sanity: path.join(cwd, '.sanity', 'runtime', 'app.js'),\n ...autoUpdates?.vendor.entries,\n },\n onwarn: onRolldownWarn,\n ...(autoUpdates\n ? {\n // Expose Rolldown's native MagicString on `renderChunk`'s `meta` so\n // the vendor named-exports plugin can edit chunks without a JS\n // dependency.\n experimental: {nativeMagicString: true},\n output: {\n entryFileNames: (chunk) =>\n vendorChunkNames!.has(chunk.name)\n ? `${VENDOR_DIR}/[name]-[hash].mjs`\n : 'static/[name]-[hash].js',\n exports: 'named',\n },\n // App-style builds default to `preserveEntrySignatures: false`, which\n // treeshakes the exports off entry chunks. Vendor chunks are loaded by\n // the browser via the import map, so their exports must survive (e.g.\n // styled-components' native ESM exports). `exports-only` keeps exports\n // for entries that have them, while the export-less `sanity` app entry\n // still bundles as before.\n preserveEntrySignatures: 'exports-only',\n }\n : {}),\n },\n }\n }\n\n return viteConfig\n}\n\nfunction onRolldownWarn(warning: Rolldown.RolldownLog, warn: Rolldown.LoggingFunction) {\n if (suppressUnusedImport(warning)) {\n return\n }\n\n warn(warning)\n}\n\nfunction suppressUnusedImport(warning: Rolldown.RolldownLog & {ids?: string[]}): boolean {\n if (warning.code !== 'UNUSED_EXTERNAL_IMPORT') return false\n\n // Suppress:\n // ```\n // \"useDebugValue\" is imported from external module \"react\"…\n // ```\n if (warning.names?.includes('useDebugValue')) {\n warning.names = warning.names.filter((n) => n !== 'useDebugValue')\n if (warning.names.length === 0) return true\n }\n\n // If some library does something unexpected, we suppress since it isn't actionable\n if (warning.ids?.every((id) => id.includes('/node_modules/') || id.includes('\\\\node_modules\\\\')))\n return true\n\n return false\n}\n\n/**\n * Re-asserts the critical parts of the default config after a userland vite\n * config (`vite` in `sanity.cli.ts`) has been applied.\n *\n * Everything `getViteConfig` sets under `build.rolldownOptions` is load-bearing:\n * the `input` entries (the studio entry plus, for auto-updating studios/apps,\n * the vendor entries), `preserveEntrySignatures`, the `experimental` flags the\n * vendor plugins rely on, and the `output` chunk naming. A userland config that\n * returns a brand-new object for any of these would silently break the build\n * (e.g. vendor chunks never emitted while the bundle still treats them as\n * external), so the default `rolldownOptions` are deep-merged back over the\n * userland config: userland additions survive, replacements of critical\n * options are healed.\n *\n * @param config - User-modified configuration\n * @param defaultConfig - The configuration produced by `getViteConfig`, before the userland config was applied\n * @returns Merged configuration\n * @internal\n */\nexport async function finalizeViteConfig(\n config: InlineConfig,\n defaultConfig: InlineConfig,\n): Promise<InlineConfig> {\n if (typeof config.build?.rolldownOptions?.input !== 'object') {\n throw new TypeError(\n 'Vite config must contain `build.rolldownOptions.input`, and it must be an object',\n )\n }\n\n if (!config.root) {\n throw new Error(\n 'Vite config must contain `root` property, and must point to the Sanity root directory',\n )\n }\n\n return mergeConfig(config, {\n build: {\n rolldownOptions: defaultConfig.build?.rolldownOptions ?? {},\n },\n })\n}\n\n/**\n * Merge user-provided Vite configuration object or function\n *\n * @param defaultConfig - Default configuration object\n * @param userConfig - User-provided configuration object or function\n * @returns Merged configuration\n * @internal\n */\nexport async function extendViteConfigWithUserConfig(\n env: ConfigEnv,\n defaultConfig: InlineConfig,\n userConfig: UserViteConfig,\n): Promise<InlineConfig> {\n let config = defaultConfig\n\n if (typeof userConfig === 'function') {\n debug('Extending vite config using user-specified function')\n config = await userConfig(config, env)\n } else if (typeof userConfig === 'object') {\n debug('Merging vite config using user-specified object')\n config = mergeConfig(config, userConfig)\n }\n\n return config\n}\n"],"names":["path","babel","findProjectRoot","getCliTelemetry","workbenchVitePlugins","viteReact","reactCompilerPreset","debug","esmExternalRequirePlugin","mergeConfig","SANITY_CACHE_DIR","sanitySchemaExtractionPlugin","VENDOR_DIR","createExternalFromImportMap","normalizeBasePath","sanityBuildEntries","sanityFaviconsPlugin","sanityRuntimeRewritePlugin","createVendorNamedExportsPlugin","getDefaultFaviconsPath","getViteConfig","options","additionalPlugins","autoUpdates","basePath","rawBasePath","cwd","entries","exposes","isApp","isWorkbenchApp","minify","mode","outputDir","reactCompiler","schemaExtraction","server","sourceMap","workbenchAppId","configPath","customFaviconsPath","join","defaultFaviconsPath","staticPath","envVars","getEnvironmentVariables","sharedPlugins","presets","enabled","additionalPatterns","watchPatterns","enforceRequiredFields","outputPath","telemetryLogger","workDir","workspaceName","workspace","viteConfig","base","build","outDir","resolve","sourcemap","cacheDir","configFile","define","__SANITY_BUILD_TIMESTAMP__","JSON","stringify","Date","now","__SANITY_STAGING__","process","env","SANITY_INTERNAL_ENV","PKG_BUILD_VERSION","envPrefix","logLevel","plugins","appId","staticUrlPath","dedupe","tsconfigPaths","root","host","port","strictPort","warmup","clientFiles","push","vendor","namesByChunkName","external","imports","Object","fromEntries","values","specifiersByChunkName","map","specifier","vendorChunkNames","Set","keys","assetsDir","emptyOutDir","rolldownOptions","input","sanity","onwarn","onRolldownWarn","experimental","nativeMagicString","output","entryFileNames","chunk","has","name","exports","preserveEntrySignatures","warning","warn","suppressUnusedImport","code","names","includes","filter","n","length","ids","every","id","finalizeViteConfig","config","defaultConfig","TypeError","Error","extendViteConfigWithUserConfig","userConfig"],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import { styleText } from 'node:util';
2
+ import { isInteractive } from '@sanity/cli-core';
3
+ import { select } from '@sanity/cli-core/ux';
4
+ /**
5
+ * Handle prerelease versions that cannot be resolved by the auto-updates CDN.
6
+ *
7
+ * In unattended or non-interactive mode, exits with an error. In interactive mode,
8
+ * prompts the user to either disable auto-updates for this build or cancel.
9
+ *
10
+ * Does not return if the build should be cancelled (exits via `output.error`).
11
+ */ export async function handlePrereleaseVersions({ output, unattendedMode, unresolvedPrerelease }) {
12
+ const prereleaseMessage = `The following packages are using prerelease versions not yet available on the auto-updates CDN:\n\n` + `${unresolvedPrerelease.map((mod)=>` - ${mod.pkg} (${mod.version})`).join('\n')}\n\n` + `Auto-updates cannot be used with prerelease versions. To re-enable auto-updates later, ` + `switch to a non-prerelease version locally and deploy again.`;
13
+ if (unattendedMode || !isInteractive()) {
14
+ output.error(`${prereleaseMessage}\n\n` + `Cannot build with auto-updates in unattended mode when using prerelease versions. ` + `Either switch to a non-prerelease version, or use --no-auto-updates to build without auto-updates.`, {
15
+ exit: 1
16
+ });
17
+ // output.error with exit: 1 throws, but TypeScript doesn't know that
18
+ return;
19
+ }
20
+ const choice = await select({
21
+ choices: [
22
+ {
23
+ name: 'Disable auto-updates for this build and continue',
24
+ value: 'disable-auto-updates'
25
+ },
26
+ {
27
+ name: 'Cancel build',
28
+ value: 'cancel'
29
+ }
30
+ ],
31
+ default: 'disable-auto-updates',
32
+ message: styleText('yellow', prereleaseMessage)
33
+ });
34
+ if (choice === 'cancel') {
35
+ output.error('Declined to continue with build', {
36
+ exit: 1
37
+ });
38
+ // output.error with exit: 1 throws, but TypeScript doesn't know that
39
+ return;
40
+ }
41
+ output.warn('Auto-updates disabled for this build');
42
+ }
43
+
44
+ //# sourceMappingURL=handlePrereleaseVersions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/actions/build/handlePrereleaseVersions.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {isInteractive, type Output} from '@sanity/cli-core'\nimport {select} from '@sanity/cli-core/ux'\n\nimport {type UnresolvedPrerelease} from '../../util/compareDependencyVersions.js'\n\n/**\n * Handle prerelease versions that cannot be resolved by the auto-updates CDN.\n *\n * In unattended or non-interactive mode, exits with an error. In interactive mode,\n * prompts the user to either disable auto-updates for this build or cancel.\n *\n * Does not return if the build should be cancelled (exits via `output.error`).\n */\nexport async function handlePrereleaseVersions({\n output,\n unattendedMode,\n unresolvedPrerelease,\n}: {\n output: Output\n unattendedMode: boolean\n unresolvedPrerelease: UnresolvedPrerelease[]\n}): Promise<void> {\n const prereleaseMessage =\n `The following packages are using prerelease versions not yet available on the auto-updates CDN:\\n\\n` +\n `${unresolvedPrerelease.map((mod) => ` - ${mod.pkg} (${mod.version})`).join('\\n')}\\n\\n` +\n `Auto-updates cannot be used with prerelease versions. To re-enable auto-updates later, ` +\n `switch to a non-prerelease version locally and deploy again.`\n\n if (unattendedMode || !isInteractive()) {\n output.error(\n `${prereleaseMessage}\\n\\n` +\n `Cannot build with auto-updates in unattended mode when using prerelease versions. ` +\n `Either switch to a non-prerelease version, or use --no-auto-updates to build without auto-updates.`,\n {exit: 1},\n )\n // output.error with exit: 1 throws, but TypeScript doesn't know that\n return\n }\n\n const choice = await select({\n choices: [\n {\n name: 'Disable auto-updates for this build and continue',\n value: 'disable-auto-updates',\n },\n {name: 'Cancel build', value: 'cancel'},\n ],\n default: 'disable-auto-updates',\n message: styleText('yellow', prereleaseMessage),\n })\n\n if (choice === 'cancel') {\n output.error('Declined to continue with build', {exit: 1})\n // output.error with exit: 1 throws, but TypeScript doesn't know that\n return\n }\n\n output.warn('Auto-updates disabled for this build')\n}\n"],"names":["styleText","isInteractive","select","handlePrereleaseVersions","output","unattendedMode","unresolvedPrerelease","prereleaseMessage","map","mod","pkg","version","join","error","exit","choice","choices","name","value","default","message","warn"],"mappings":"AAAA,SAAQA,SAAS,QAAO,YAAW;AAEnC,SAAQC,aAAa,QAAoB,mBAAkB;AAC3D,SAAQC,MAAM,QAAO,sBAAqB;AAI1C;;;;;;;CAOC,GACD,OAAO,eAAeC,yBAAyB,EAC7CC,MAAM,EACNC,cAAc,EACdC,oBAAoB,EAKrB;IACC,MAAMC,oBACJ,CAAC,mGAAmG,CAAC,GACrG,GAAGD,qBAAqBE,GAAG,CAAC,CAACC,MAAQ,CAAC,GAAG,EAAEA,IAAIC,GAAG,CAAC,EAAE,EAAED,IAAIE,OAAO,CAAC,CAAC,CAAC,EAAEC,IAAI,CAAC,MAAM,IAAI,CAAC,GACvF,CAAC,uFAAuF,CAAC,GACzF,CAAC,4DAA4D,CAAC;IAEhE,IAAIP,kBAAkB,CAACJ,iBAAiB;QACtCG,OAAOS,KAAK,CACV,GAAGN,kBAAkB,IAAI,CAAC,GACxB,CAAC,kFAAkF,CAAC,GACpF,CAAC,kGAAkG,CAAC,EACtG;YAACO,MAAM;QAAC;QAEV,qEAAqE;QACrE;IACF;IAEA,MAAMC,SAAS,MAAMb,OAAO;QAC1Bc,SAAS;YACP;gBACEC,MAAM;gBACNC,OAAO;YACT;YACA;gBAACD,MAAM;gBAAgBC,OAAO;YAAQ;SACvC;QACDC,SAAS;QACTC,SAASpB,UAAU,UAAUO;IAC/B;IAEA,IAAIQ,WAAW,UAAU;QACvBX,OAAOS,KAAK,CAAC,mCAAmC;YAACC,MAAM;QAAC;QACxD,qEAAqE;QACrE;IACF;IAEAV,OAAOiB,IAAI,CAAC;AACd"}
@@ -20,10 +20,22 @@ import { parse as parseHtml } from 'node-html-parser';
20
20
  importMapEl.type = 'importmap';
21
21
  const newTimestamp = \`/t\${Math.floor(Date.now() / 1000)}\`;
22
22
 
23
+ function isSanityCdnHost(hostname) {
24
+ return /^sanity-cdn\\.[a-zA-Z]+$/.test(hostname);
25
+ }
26
+
27
+ function isSanityCdnUrl(urlStr) {
28
+ try {
29
+ return isSanityCdnHost(new URL(urlStr).hostname);
30
+ } catch {
31
+ return false;
32
+ }
33
+ }
34
+
23
35
  function replaceTimestamp(urlStr) {
24
36
  try {
25
37
  const url = new URL(urlStr);
26
- if (/^sanity-cdn\\.[a-zA-Z]+$/.test(url.hostname)) {
38
+ if (isSanityCdnHost(url.hostname)) {
27
39
  url.pathname = url.pathname.replace(/\\/t\\d+/, newTimestamp);
28
40
  }
29
41
  return url.toString();
@@ -47,6 +59,55 @@ import { parse as parseHtml } from 'node-html-parser';
47
59
  linkEl.href = replaceTimestamp(cssUrl);
48
60
  document.head.appendChild(linkEl);
49
61
  }
62
+
63
+ // The CDN serves the \`sanity\` module via a cross-origin 302
64
+ // (sanity-cdn.com -> modules.sanity-cdn.com). WebKit mishandles a
65
+ // \`modulepreload\` that follows a cross-origin redirect: it forces the CORS
66
+ // credentials flag true even for \`crossorigin="anonymous"\`, then rejects the
67
+ // redirect because the CDN sends no \`Access-Control-Allow-Credentials\`,
68
+ // which blanks the studio. (This is why these hints were reverted; see
69
+ // PR #1400.)
70
+ //
71
+ // \`preconnect\` only warms a socket; it never follows the redirect or fetches
72
+ // the module, so it is safe in every engine and runs unconditionally.
73
+ const firstCdnImport = Object.values(imports).find(isSanityCdnUrl);
74
+
75
+ if (firstCdnImport) {
76
+ const preconnectEl = document.createElement('link');
77
+ preconnectEl.rel = 'preconnect';
78
+ preconnectEl.href = new URL(firstCdnImport).origin;
79
+ // Module fetches are CORS; without crossorigin the warmed socket is not reused.
80
+ preconnectEl.crossOrigin = 'anonymous';
81
+ document.head.appendChild(preconnectEl);
82
+ }
83
+
84
+ // \`modulepreload\` is the hint that follows the redirect and can blank the
85
+ // studio in WebKit, so it is gated behind a positive allowlist: it runs only
86
+ // for engines confirmed to handle the cross-origin redirect, i.e. Chromium or
87
+ // Gecko. Every Chromium variant (Edge, Opera, Samsung Internet, ...) carries
88
+ // the \`Chrome\` token, so matching \`Chrom(e|ium)|Firefox\` covers them without
89
+ // enumerating brands. The iOS device-name exclusion is the hard guard for the
90
+ // brick-prone platform: every iOS browser is WebKit regardless of brand, and
91
+ // iOS in-app webviews carry messy UAs, so nothing on an iOS device is ever
92
+ // treated as safe. Anything unrecognised falls through to no preload, costing
93
+ // a missed download rather than bricking the studio.
94
+ const userAgent = typeof navigator === 'undefined' ? '' : navigator.userAgent || '';
95
+ const isKnownSafeEngine =
96
+ !/\\b(iPad|iPhone|iPod)\\b/.test(userAgent) && /Chrom(e|ium)|Firefox/.test(userAgent);
97
+
98
+ // The href reuses replaceTimestamp so it matches the importmap entry exactly;
99
+ // a stale timestamp here would double-fetch the largest chunk.
100
+ const sanityModuleUrl = imports['sanity'];
101
+ if (isKnownSafeEngine && typeof sanityModuleUrl === 'string' && isSanityCdnUrl(sanityModuleUrl)) {
102
+ const preloadEl = document.createElement('link');
103
+ preloadEl.rel = 'modulepreload';
104
+ preloadEl.href = replaceTimestamp(sanityModuleUrl);
105
+ // Must match the preconnect's credentials mode, otherwise the browser
106
+ // treats them as separate connections and the warmed cross-origin socket
107
+ // is not reused for this fetch.
108
+ preloadEl.crossOrigin = 'anonymous';
109
+ document.head.appendChild(preloadEl);
110
+ }
50
111
  </script>`;
51
112
  /**
52
113
  * @internal
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/actions/build/renderDocumentWorker/addTimestampImportMapScriptToHtml.ts"],"sourcesContent":["import {parse as parseHtml} from 'node-html-parser'\n\n/**\n * This script takes the import map from the `#__imports` script tag,\n * modifies relevant URLs that match the sanity-cdn hostname by replacing\n * the existing timestamp in the sanity-cdn URLs with a new runtime timestamp,\n * and injects the modified import map back into the HTML.\n *\n * It also synchronously creates `<link rel=\"stylesheet\">` tags for each CDN\n * CSS URL with a fresh timestamp.\n *\n * This will be injected into the HTML of the user's bundle.\n *\n * Note that this is in a separate constants file to prevent \"Cannot access\n * before initialization\" errors.\n */\nconst TIMESTAMPED_IMPORTMAP_INJECTOR_SCRIPT = `<script>\n // auto-generated script to add import map with timestamp\n const importsJson = document.getElementById('__imports')?.textContent;\n const { imports = {}, css = [], ...rest } = importsJson ? JSON.parse(importsJson) : {};\n const importMapEl = document.createElement('script');\n importMapEl.type = 'importmap';\n const newTimestamp = \\`/t\\${Math.floor(Date.now() / 1000)}\\`;\n\n function replaceTimestamp(urlStr) {\n try {\n const url = new URL(urlStr);\n if (/^sanity-cdn\\\\.[a-zA-Z]+$/.test(url.hostname)) {\n url.pathname = url.pathname.replace(/\\\\/t\\\\d+/, newTimestamp);\n }\n return url.toString();\n } catch {\n return urlStr;\n }\n }\n\n importMapEl.textContent = JSON.stringify({\n imports: Object.fromEntries(\n Object.entries(imports).map(([specifier, path]) => [specifier, replaceTimestamp(path)])\n ),\n ...rest,\n });\n document.head.appendChild(importMapEl);\n\n // Creates <link rel=\"stylesheet\"> tags with fresh timestamps.\n for (const cssUrl of css) {\n const linkEl = document.createElement('link');\n linkEl.rel = 'stylesheet';\n linkEl.href = replaceTimestamp(cssUrl);\n document.head.appendChild(linkEl);\n }\n</script>`\n\n/**\n * @internal\n */\nexport function addTimestampedImportMapScriptToHtml(\n html: string,\n importMap?: {imports?: Record<string, string>},\n autoUpdatesCssUrls?: string[],\n): string {\n if (!importMap) return html\n\n let root = parseHtml(html)\n let htmlEl = root.querySelector('html')\n if (!htmlEl) {\n const oldRoot = root\n root = parseHtml('<html></html>')\n htmlEl = root.querySelector('html')!\n htmlEl.append(oldRoot)\n }\n\n let headEl = htmlEl.querySelector('head')\n\n if (!headEl) {\n htmlEl.insertAdjacentHTML('afterbegin', '<head></head>')\n headEl = root.querySelector('head')!\n }\n\n // Include CSS URLs in the __imports JSON so the runtime script can create\n // <link> tags with fresh timestamps synchronously during head parsing.\n const importMapWithCss =\n autoUpdatesCssUrls && autoUpdatesCssUrls.length > 0\n ? {...importMap, css: autoUpdatesCssUrls}\n : importMap\n\n headEl.insertAdjacentHTML(\n 'beforeend',\n `<script type=\"application/json\" id=\"__imports\">${JSON.stringify(importMapWithCss)}</script>`,\n )\n\n headEl.insertAdjacentHTML('beforeend', TIMESTAMPED_IMPORTMAP_INJECTOR_SCRIPT)\n return root.outerHTML\n}\n"],"names":["parse","parseHtml","TIMESTAMPED_IMPORTMAP_INJECTOR_SCRIPT","addTimestampedImportMapScriptToHtml","html","importMap","autoUpdatesCssUrls","root","htmlEl","querySelector","oldRoot","append","headEl","insertAdjacentHTML","importMapWithCss","length","css","JSON","stringify","outerHTML"],"mappings":"AAAA,SAAQA,SAASC,SAAS,QAAO,mBAAkB;AAEnD;;;;;;;;;;;;;CAaC,GACD,MAAMC,wCAAwC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SAmCtC,CAAC;AAEV;;CAEC,GACD,OAAO,SAASC,oCACdC,IAAY,EACZC,SAA8C,EAC9CC,kBAA6B;IAE7B,IAAI,CAACD,WAAW,OAAOD;IAEvB,IAAIG,OAAON,UAAUG;IACrB,IAAII,SAASD,KAAKE,aAAa,CAAC;IAChC,IAAI,CAACD,QAAQ;QACX,MAAME,UAAUH;QAChBA,OAAON,UAAU;QACjBO,SAASD,KAAKE,aAAa,CAAC;QAC5BD,OAAOG,MAAM,CAACD;IAChB;IAEA,IAAIE,SAASJ,OAAOC,aAAa,CAAC;IAElC,IAAI,CAACG,QAAQ;QACXJ,OAAOK,kBAAkB,CAAC,cAAc;QACxCD,SAASL,KAAKE,aAAa,CAAC;IAC9B;IAEA,0EAA0E;IAC1E,uEAAuE;IACvE,MAAMK,mBACJR,sBAAsBA,mBAAmBS,MAAM,GAAG,IAC9C;QAAC,GAAGV,SAAS;QAAEW,KAAKV;IAAkB,IACtCD;IAENO,OAAOC,kBAAkB,CACvB,aACA,CAAC,+CAA+C,EAAEI,KAAKC,SAAS,CAACJ,kBAAkB,SAAS,CAAC;IAG/FF,OAAOC,kBAAkB,CAAC,aAAaX;IACvC,OAAOK,KAAKY,SAAS;AACvB"}
1
+ {"version":3,"sources":["../../../../src/actions/build/renderDocumentWorker/addTimestampImportMapScriptToHtml.ts"],"sourcesContent":["import {parse as parseHtml} from 'node-html-parser'\n\n/**\n * This script takes the import map from the `#__imports` script tag,\n * modifies relevant URLs that match the sanity-cdn hostname by replacing\n * the existing timestamp in the sanity-cdn URLs with a new runtime timestamp,\n * and injects the modified import map back into the HTML.\n *\n * It also synchronously creates `<link rel=\"stylesheet\">` tags for each CDN\n * CSS URL with a fresh timestamp.\n *\n * This will be injected into the HTML of the user's bundle.\n *\n * Note that this is in a separate constants file to prevent \"Cannot access\n * before initialization\" errors.\n */\nconst TIMESTAMPED_IMPORTMAP_INJECTOR_SCRIPT = `<script>\n // auto-generated script to add import map with timestamp\n const importsJson = document.getElementById('__imports')?.textContent;\n const { imports = {}, css = [], ...rest } = importsJson ? JSON.parse(importsJson) : {};\n const importMapEl = document.createElement('script');\n importMapEl.type = 'importmap';\n const newTimestamp = \\`/t\\${Math.floor(Date.now() / 1000)}\\`;\n\n function isSanityCdnHost(hostname) {\n return /^sanity-cdn\\\\.[a-zA-Z]+$/.test(hostname);\n }\n\n function isSanityCdnUrl(urlStr) {\n try {\n return isSanityCdnHost(new URL(urlStr).hostname);\n } catch {\n return false;\n }\n }\n\n function replaceTimestamp(urlStr) {\n try {\n const url = new URL(urlStr);\n if (isSanityCdnHost(url.hostname)) {\n url.pathname = url.pathname.replace(/\\\\/t\\\\d+/, newTimestamp);\n }\n return url.toString();\n } catch {\n return urlStr;\n }\n }\n\n importMapEl.textContent = JSON.stringify({\n imports: Object.fromEntries(\n Object.entries(imports).map(([specifier, path]) => [specifier, replaceTimestamp(path)])\n ),\n ...rest,\n });\n document.head.appendChild(importMapEl);\n\n // Creates <link rel=\"stylesheet\"> tags with fresh timestamps.\n for (const cssUrl of css) {\n const linkEl = document.createElement('link');\n linkEl.rel = 'stylesheet';\n linkEl.href = replaceTimestamp(cssUrl);\n document.head.appendChild(linkEl);\n }\n\n // The CDN serves the \\`sanity\\` module via a cross-origin 302\n // (sanity-cdn.com -> modules.sanity-cdn.com). WebKit mishandles a\n // \\`modulepreload\\` that follows a cross-origin redirect: it forces the CORS\n // credentials flag true even for \\`crossorigin=\"anonymous\"\\`, then rejects the\n // redirect because the CDN sends no \\`Access-Control-Allow-Credentials\\`,\n // which blanks the studio. (This is why these hints were reverted; see\n // PR #1400.)\n //\n // \\`preconnect\\` only warms a socket; it never follows the redirect or fetches\n // the module, so it is safe in every engine and runs unconditionally.\n const firstCdnImport = Object.values(imports).find(isSanityCdnUrl);\n\n if (firstCdnImport) {\n const preconnectEl = document.createElement('link');\n preconnectEl.rel = 'preconnect';\n preconnectEl.href = new URL(firstCdnImport).origin;\n // Module fetches are CORS; without crossorigin the warmed socket is not reused.\n preconnectEl.crossOrigin = 'anonymous';\n document.head.appendChild(preconnectEl);\n }\n\n // \\`modulepreload\\` is the hint that follows the redirect and can blank the\n // studio in WebKit, so it is gated behind a positive allowlist: it runs only\n // for engines confirmed to handle the cross-origin redirect, i.e. Chromium or\n // Gecko. Every Chromium variant (Edge, Opera, Samsung Internet, ...) carries\n // the \\`Chrome\\` token, so matching \\`Chrom(e|ium)|Firefox\\` covers them without\n // enumerating brands. The iOS device-name exclusion is the hard guard for the\n // brick-prone platform: every iOS browser is WebKit regardless of brand, and\n // iOS in-app webviews carry messy UAs, so nothing on an iOS device is ever\n // treated as safe. Anything unrecognised falls through to no preload, costing\n // a missed download rather than bricking the studio.\n const userAgent = typeof navigator === 'undefined' ? '' : navigator.userAgent || '';\n const isKnownSafeEngine =\n !/\\\\b(iPad|iPhone|iPod)\\\\b/.test(userAgent) && /Chrom(e|ium)|Firefox/.test(userAgent);\n\n // The href reuses replaceTimestamp so it matches the importmap entry exactly;\n // a stale timestamp here would double-fetch the largest chunk.\n const sanityModuleUrl = imports['sanity'];\n if (isKnownSafeEngine && typeof sanityModuleUrl === 'string' && isSanityCdnUrl(sanityModuleUrl)) {\n const preloadEl = document.createElement('link');\n preloadEl.rel = 'modulepreload';\n preloadEl.href = replaceTimestamp(sanityModuleUrl);\n // Must match the preconnect's credentials mode, otherwise the browser\n // treats them as separate connections and the warmed cross-origin socket\n // is not reused for this fetch.\n preloadEl.crossOrigin = 'anonymous';\n document.head.appendChild(preloadEl);\n }\n</script>`\n\n/**\n * @internal\n */\nexport function addTimestampedImportMapScriptToHtml(\n html: string,\n importMap?: {imports?: Record<string, string>},\n autoUpdatesCssUrls?: string[],\n): string {\n if (!importMap) return html\n\n let root = parseHtml(html)\n let htmlEl = root.querySelector('html')\n if (!htmlEl) {\n const oldRoot = root\n root = parseHtml('<html></html>')\n htmlEl = root.querySelector('html')!\n htmlEl.append(oldRoot)\n }\n\n let headEl = htmlEl.querySelector('head')\n\n if (!headEl) {\n htmlEl.insertAdjacentHTML('afterbegin', '<head></head>')\n headEl = root.querySelector('head')!\n }\n\n // Include CSS URLs in the __imports JSON so the runtime script can create\n // <link> tags with fresh timestamps synchronously during head parsing.\n const importMapWithCss =\n autoUpdatesCssUrls && autoUpdatesCssUrls.length > 0\n ? {...importMap, css: autoUpdatesCssUrls}\n : importMap\n\n headEl.insertAdjacentHTML(\n 'beforeend',\n `<script type=\"application/json\" id=\"__imports\">${JSON.stringify(importMapWithCss)}</script>`,\n )\n\n headEl.insertAdjacentHTML('beforeend', TIMESTAMPED_IMPORTMAP_INJECTOR_SCRIPT)\n return root.outerHTML\n}\n"],"names":["parse","parseHtml","TIMESTAMPED_IMPORTMAP_INJECTOR_SCRIPT","addTimestampedImportMapScriptToHtml","html","importMap","autoUpdatesCssUrls","root","htmlEl","querySelector","oldRoot","append","headEl","insertAdjacentHTML","importMapWithCss","length","css","JSON","stringify","outerHTML"],"mappings":"AAAA,SAAQA,SAASC,SAAS,QAAO,mBAAkB;AAEnD;;;;;;;;;;;;;CAaC,GACD,MAAMC,wCAAwC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SAgGtC,CAAC;AAEV;;CAEC,GACD,OAAO,SAASC,oCACdC,IAAY,EACZC,SAA8C,EAC9CC,kBAA6B;IAE7B,IAAI,CAACD,WAAW,OAAOD;IAEvB,IAAIG,OAAON,UAAUG;IACrB,IAAII,SAASD,KAAKE,aAAa,CAAC;IAChC,IAAI,CAACD,QAAQ;QACX,MAAME,UAAUH;QAChBA,OAAON,UAAU;QACjBO,SAASD,KAAKE,aAAa,CAAC;QAC5BD,OAAOG,MAAM,CAACD;IAChB;IAEA,IAAIE,SAASJ,OAAOC,aAAa,CAAC;IAElC,IAAI,CAACG,QAAQ;QACXJ,OAAOK,kBAAkB,CAAC,cAAc;QACxCD,SAASL,KAAKE,aAAa,CAAC;IAC9B;IAEA,0EAA0E;IAC1E,uEAAuE;IACvE,MAAMK,mBACJR,sBAAsBA,mBAAmBS,MAAM,GAAG,IAC9C;QAAC,GAAGV,SAAS;QAAEW,KAAKV;IAAkB,IACtCD;IAENO,OAAOC,kBAAkB,CACvB,aACA,CAAC,+CAA+C,EAAEI,KAAKC,SAAS,CAACJ,kBAAkB,SAAS,CAAC;IAG/FF,OAAOC,kBAAkB,CAAC,aAAaX;IACvC,OAAOK,KAAKY,SAAS;AACvB"}
@@ -0,0 +1,3 @@
1
+ export { };
2
+
3
+ //# sourceMappingURL=compareDependencyVersions.d.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/util/compareDependencyVersions.d.ts"],"sourcesContent":["export interface CompareDependencyVersions {\n installed: string\n pkg: string\n remote: string\n}\n\nexport interface UnresolvedPrerelease {\n pkg: string\n version: string\n}\n\nexport interface CompareDependencyVersionsResult {\n mismatched: Array<CompareDependencyVersions>\n unresolvedPrerelease: Array<UnresolvedPrerelease>\n}\n"],"names":[],"mappings":"AAWA,WAGC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/cli-build",
3
- "version": "2.0.0",
3
+ "version": "3.0.0",
4
4
  "description": "Internal Sanity package for building studios and apps",
5
5
  "keywords": [
6
6
  "cli",
@@ -64,14 +64,14 @@
64
64
  "react-dom": "^19.2.7",
65
65
  "read-package-up": "^12.0.0",
66
66
  "semver": "^7.8.1",
67
- "vite": "8.1.0",
67
+ "vite": "^8.1.3",
68
68
  "zod": "^4.4.3",
69
- "@sanity/cli-core": "^2.1.2",
70
- "@sanity/workbench-cli": "^1.1.2"
69
+ "@sanity/cli-core": "^2.2.0",
70
+ "@sanity/workbench-cli": "^1.2.0"
71
71
  },
72
72
  "devDependencies": {
73
73
  "@eslint/compat": "^2.1.0",
74
- "@sanity/pkg-utils": "^10.5.8",
74
+ "@sanity/pkg-utils": "^10.8.1",
75
75
  "@swc/cli": "^0.8.1",
76
76
  "@swc/core": "^1.15.41",
77
77
  "@types/debug": "^4.1.13",
@@ -94,7 +94,7 @@
94
94
  "vitest": "^4.1.9",
95
95
  "@repo/package.config": "0.0.1",
96
96
  "@repo/tsconfig": "3.70.0",
97
- "@sanity/cli-test": "2.0.2",
97
+ "@sanity/cli-test": "3.0.0",
98
98
  "@sanity/eslint-config-cli": "^1.1.2"
99
99
  },
100
100
  "peerDependencies": {