@sanity/cli-build 0.2.2 → 1.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.
- package/dist/actions/build/buildVendorDependencies.js +42 -12
- package/dist/actions/build/buildVendorDependencies.js.map +1 -1
- package/dist/actions/build/createExternalFromImportMap.js +2 -2
- package/dist/actions/build/createExternalFromImportMap.js.map +1 -1
- package/dist/actions/build/getCjsNamedExports.js +39 -0
- package/dist/actions/build/getCjsNamedExports.js.map +1 -0
- package/dist/actions/build/getViteConfig.js +31 -23
- package/dist/actions/build/getViteConfig.js.map +1 -1
- package/dist/actions/build/vite/injectNamedExports.js +96 -0
- package/dist/actions/build/vite/injectNamedExports.js.map +1 -0
- package/dist/actions/build/vite/plugin-sanity-vendor-named-exports.js +53 -0
- package/dist/actions/build/vite/plugin-sanity-vendor-named-exports.js.map +1 -0
- package/package.json +11 -7
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
1
2
|
import path from 'node:path';
|
|
2
3
|
import { getLocalPackageDir, getLocalPackageVersion } from '@sanity/cli-core';
|
|
3
4
|
import { gt, minVersion, rcompare, satisfies } from 'semver';
|
|
4
|
-
import { build } from 'vite';
|
|
5
|
+
import { build, esmExternalRequirePlugin } from 'vite';
|
|
5
6
|
import { SANITY_CACHE_DIR } from '../../constants.js';
|
|
6
7
|
import { createExternalFromImportMap } from './createExternalFromImportMap.js';
|
|
8
|
+
import { getCjsNamedExports } from './getCjsNamedExports.js';
|
|
9
|
+
import { createVendorNamedExportsPlugin } from './vite/plugin-sanity-vendor-named-exports.js';
|
|
7
10
|
// Directory where vendor packages will be stored
|
|
8
11
|
const VENDOR_DIR = 'vendor';
|
|
9
12
|
// Define the vendor packages and their corresponding versions and entry points
|
|
@@ -43,6 +46,8 @@ const STYLED_COMPONENTS_IMPORTS = {
|
|
|
43
46
|
*/ export async function buildVendorDependencies({ basePath, cwd, isApp, outputDir }) {
|
|
44
47
|
const entry = {};
|
|
45
48
|
const imports = {};
|
|
49
|
+
// Named exports each CommonJS entry must re-expose as ESM, keyed by chunk name.
|
|
50
|
+
const namesByChunkName = {};
|
|
46
51
|
// If we're building an app, we don't need to build the styled-components package
|
|
47
52
|
const vendorImports = isApp ? VENDOR_IMPORTS : {
|
|
48
53
|
...VENDOR_IMPORTS,
|
|
@@ -83,17 +88,32 @@ const STYLED_COMPONENTS_IMPORTS = {
|
|
|
83
88
|
for (const [subpath, relativeEntryPoint] of Object.entries(subpaths)){
|
|
84
89
|
const specifier = path.posix.join(packageName, subpath);
|
|
85
90
|
const chunkName = path.posix.join(packageName, path.relative(packageName, specifier) || 'index');
|
|
86
|
-
|
|
91
|
+
const entryPath = path.join(packageDir, relativeEntryPoint);
|
|
92
|
+
entry[chunkName] = entryPath;
|
|
87
93
|
imports[specifier] = path.posix.join('/', basePath, VENDOR_DIR, `${chunkName}.mjs`);
|
|
94
|
+
// React and React-DOM ship CommonJS. Rolldown lowers a CJS entry to an ESM
|
|
95
|
+
// chunk that only emits `export default`, so collect the named exports it
|
|
96
|
+
// must additionally re-expose (see `createVendorNamedExportsPlugin`).
|
|
97
|
+
// `styled-components` is native ESM and `package.json` is JSON, so both are
|
|
98
|
+
// skipped here.
|
|
99
|
+
if (packageName in VENDOR_IMPORTS && subpath !== './package.json') {
|
|
100
|
+
const source = await readFile(entryPath, 'utf8');
|
|
101
|
+
namesByChunkName[chunkName] = await getCjsNamedExports(source, chunkName);
|
|
102
|
+
}
|
|
88
103
|
}
|
|
89
104
|
}
|
|
105
|
+
// Externals are handled by `esmExternalRequirePlugin` (below) rather than
|
|
106
|
+
// `rolldownOptions.external`: the plugin both marks them external AND rewrites
|
|
107
|
+
// CommonJS `require('react')` calls (e.g. in react-dom) into ESM imports.
|
|
108
|
+
// Also setting `rolldownOptions.external` short-circuits that rewrite, leaving a
|
|
109
|
+
// runtime `require` shim that throws in the browser.
|
|
110
|
+
const external = createExternalFromImportMap({
|
|
111
|
+
imports
|
|
112
|
+
});
|
|
90
113
|
// Use Vite to build the packages into the output directory
|
|
91
114
|
let buildResult = await build({
|
|
92
115
|
appType: 'custom',
|
|
93
116
|
build: {
|
|
94
|
-
commonjsOptions: {
|
|
95
|
-
strictRequires: 'auto'
|
|
96
|
-
},
|
|
97
117
|
emptyOutDir: false,
|
|
98
118
|
lib: {
|
|
99
119
|
entry,
|
|
@@ -103,19 +123,19 @@ const STYLED_COMPONENTS_IMPORTS = {
|
|
|
103
123
|
},
|
|
104
124
|
minify: true,
|
|
105
125
|
outDir: path.join(outputDir, VENDOR_DIR),
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
126
|
+
rolldownOptions: {
|
|
127
|
+
// Expose Rolldown's native MagicString on `renderChunk`'s `meta` so the
|
|
128
|
+
// vendor named-exports plugin can edit chunks without a JS dependency.
|
|
129
|
+
experimental: {
|
|
130
|
+
nativeMagicString: true
|
|
131
|
+
},
|
|
110
132
|
output: {
|
|
111
133
|
chunkFileNames: '[name]-[hash].mjs',
|
|
112
134
|
entryFileNames: '[name]-[hash].mjs',
|
|
113
135
|
exports: 'named',
|
|
114
136
|
format: 'es'
|
|
115
137
|
},
|
|
116
|
-
treeshake:
|
|
117
|
-
preset: 'recommended'
|
|
118
|
-
}
|
|
138
|
+
treeshake: true
|
|
119
139
|
}
|
|
120
140
|
},
|
|
121
141
|
// Define a custom cache directory so that sanity's vite cache
|
|
@@ -127,6 +147,16 @@ const STYLED_COMPONENTS_IMPORTS = {
|
|
|
127
147
|
},
|
|
128
148
|
logLevel: 'silent',
|
|
129
149
|
mode: 'production',
|
|
150
|
+
plugins: [
|
|
151
|
+
// Re-expose CommonJS named exports (react, react-dom) as real ESM exports;
|
|
152
|
+
// Rolldown only emits `export default` for a CommonJS entry.
|
|
153
|
+
createVendorNamedExportsPlugin(namesByChunkName),
|
|
154
|
+
// Rewrite external `require(...)` (e.g. react-dom requiring react) into ESM
|
|
155
|
+
// imports so the vendored output runs in the browser without `require`.
|
|
156
|
+
esmExternalRequirePlugin({
|
|
157
|
+
external
|
|
158
|
+
})
|
|
159
|
+
],
|
|
130
160
|
root: cwd
|
|
131
161
|
});
|
|
132
162
|
buildResult = Array.isArray(buildResult) ? buildResult : [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/build/buildVendorDependencies.ts"],"sourcesContent":["import path from 'node:path'\n\nimport {getLocalPackageDir, getLocalPackageVersion} from '@sanity/cli-core'\nimport {gt, minVersion, rcompare, satisfies} from 'semver'\nimport {build} from 'vite'\n\nimport {SANITY_CACHE_DIR} from '../../constants.js'\nimport {createExternalFromImportMap} from './createExternalFromImportMap.js'\n\n// Directory where vendor packages will be stored\nconst VENDOR_DIR = 'vendor'\n\n/**\n * A type representing the imports of vendor packages, defining specific entry\n * points for various versions and subpaths of the packages.\n *\n * The `VendorImports` object is used to build ESM browser-compatible versions\n * of the specified packages. This approach ensures that the appropriate version\n * and entry points are used for each package, enabling compatibility and proper\n * functionality in the browser environment.\n *\n * ## Rationale\n *\n * The rationale for this structure is to handle different versions of the\n * packages carefully, especially major versions. Major version bumps often\n * introduce breaking changes, so the module scheme for the package needs to be\n * checked when there is a major version update. However, minor and patch\n * versions are generally backward compatible, so they are handled more\n * leniently. By assuming that new minor versions are compatible, we avoid\n * unnecessary warnings and streamline the update process.\n *\n * If a new minor version introduces an additional subpath export within the\n * package of this version range, the corresponding package can add a more\n * specific version range that includes the new subpath. This design allows for\n * flexibility and ease of maintenance, ensuring that the latest features and\n * fixes are incorporated without extensive manual intervention.\n *\n * An additional subpath export within the package of this version range that\n * could cause the build to break if that new export is used, can be treated as\n * a bug fix. It might make more sense to our users that this new subpath isn't\n * supported yet until we address it as a bug fix. This approach helps maintain\n * stability and prevents unexpected issues during the build process.\n *\n * ## Structure\n * The `VendorImports` type is a nested object where:\n * - The keys at the first level represent the package names.\n * - The keys at the second level represent the version ranges (e.g., `^19.0.0`).\n * - The keys at the third level represent the subpaths within the package (e.g., `.` for the main entry point).\n * - The values at the third level are the relative paths to the corresponding entry points within the package.\n *\n * This structure allows for precise specification of the entry points for\n * different versions and subpaths, ensuring that the correct files are used\n * during the build process.\n */\ntype VendorImports = {\n [packageName: string]: {\n [versionRange: string]: {\n [subpath: string]: string\n }\n }\n}\n\n// Define the vendor packages and their corresponding versions and entry points\nconst VENDOR_IMPORTS: VendorImports = {\n react: {\n '^19.2.0': {\n '.': './cjs/react.production.js',\n './compiler-runtime': './cjs/react-compiler-runtime.production.js',\n './jsx-dev-runtime': './cjs/react-jsx-dev-runtime.production.js',\n './jsx-runtime': './cjs/react-jsx-runtime.production.js',\n './package.json': './package.json',\n },\n },\n 'react-dom': {\n '^19.2.0': {\n '.': './cjs/react-dom.production.js',\n './client': './cjs/react-dom-client.production.js',\n './package.json': './package.json',\n './server': './cjs/react-dom-server-legacy.browser.production.js',\n './server.browser': './cjs/react-dom-server-legacy.browser.production.js',\n './static': './cjs/react-dom-server.browser.production.js',\n './static.browser': './cjs/react-dom-server.browser.production.js',\n },\n },\n}\n\nconst STYLED_COMPONENTS_IMPORTS = {\n 'styled-components': {\n '^6.1.0': {\n '.': './dist/styled-components.browser.esm.js',\n './package.json': './package.json',\n },\n },\n}\n\ninterface VendorBuildOptions {\n basePath: string\n cwd: string\n isApp: boolean\n outputDir: string\n}\n\n/**\n * Builds the ESM browser compatible versions of the vendor packages\n * specified in VENDOR_IMPORTS. Returns the `imports` object of an import map.\n */\nexport async function buildVendorDependencies({\n basePath,\n cwd,\n isApp,\n outputDir,\n}: VendorBuildOptions): Promise<Record<string, string>> {\n const entry: Record<string, string> = {}\n const imports: Record<string, string> = {}\n\n // If we're building an app, we don't need to build the styled-components package\n const vendorImports = isApp ? VENDOR_IMPORTS : {...VENDOR_IMPORTS, ...STYLED_COMPONENTS_IMPORTS}\n\n // Iterate over each package and its version ranges in VENDOR_IMPORTS\n for (const [packageName, ranges] of Object.entries(vendorImports)) {\n const version = await getLocalPackageVersion(packageName, cwd)\n if (!version) {\n throw new Error(`Could not get version for '${packageName}'`)\n }\n\n // Sort version ranges in descending order\n const sortedRanges = Object.keys(ranges).toSorted((range1, range2) => {\n const min1 = minVersion(range1)\n const min2 = minVersion(range2)\n\n if (!min1) throw new Error(`Could not parse range '${range1}'`)\n if (!min2) throw new Error(`Could not parse range '${range2}'`)\n\n // sort them in reverse so we can rely on array `.find` below\n return rcompare(min1.version, min2.version)\n })\n\n // Find the first version range that satisfies the package version\n const matchedRange = sortedRanges.find((range) => satisfies(version, range))\n\n if (!matchedRange) {\n const min = minVersion(sortedRanges.at(-1)!)\n if (!min) {\n throw new Error(`Could not find a minimum version for package '${packageName}'`)\n }\n\n if (gt(min.version, version)) {\n throw new Error(`Package '${packageName}' requires at least ${min.version}.`)\n }\n\n throw new Error(`Version '${version}' of package '${packageName}' is not supported yet.`)\n }\n\n const subpaths = ranges[matchedRange]\n\n // Resolve the actual package directory using Node module resolution,\n // so that hoisted packages in monorepos/workspaces are found correctly\n const packageDir = getLocalPackageDir(packageName, cwd)\n\n // Iterate over each subpath and its corresponding entry point\n for (const [subpath, relativeEntryPoint] of Object.entries(subpaths)) {\n const specifier = path.posix.join(packageName, subpath)\n const chunkName = path.posix.join(\n packageName,\n path.relative(packageName, specifier) || 'index',\n )\n\n entry[chunkName] = path.join(packageDir, relativeEntryPoint)\n imports[specifier] = path.posix.join('/', basePath, VENDOR_DIR, `${chunkName}.mjs`)\n }\n }\n\n // removes the `RollupWatcher` type\n type BuildResult = Exclude<Awaited<ReturnType<typeof build>>, {close: unknown}>\n\n // Use Vite to build the packages into the output directory\n let buildResult = (await build({\n appType: 'custom',\n build: {\n commonjsOptions: {strictRequires: 'auto'},\n emptyOutDir: false, // Rely on CLI to do this\n lib: {entry, formats: ['es']},\n minify: true,\n outDir: path.join(outputDir, VENDOR_DIR),\n rollupOptions: {\n external: createExternalFromImportMap({imports}),\n output: {\n chunkFileNames: '[name]-[hash].mjs',\n entryFileNames: '[name]-[hash].mjs',\n exports: 'named',\n format: 'es',\n },\n treeshake: {preset: 'recommended'},\n },\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-vendor`,\n configFile: false,\n define: {'process.env.NODE_ENV': JSON.stringify('production')},\n logLevel: 'silent',\n mode: 'production',\n root: cwd,\n })) as BuildResult\n\n buildResult = Array.isArray(buildResult) ? buildResult : [buildResult]\n\n // Create a map of the original import specifiers to their hashed filenames\n const hashedImports: Record<string, string> = {}\n const output = buildResult.flatMap((i) => i.output)\n\n for (const chunk of output) {\n if (chunk.type === 'asset') continue\n\n for (const [specifier, originalPath] of Object.entries(imports)) {\n if (originalPath.endsWith(`${chunk.name}.mjs`)) {\n hashedImports[specifier] = path.posix.join('/', basePath, VENDOR_DIR, chunk.fileName)\n }\n }\n }\n\n return hashedImports\n}\n"],"names":["path","getLocalPackageDir","getLocalPackageVersion","gt","minVersion","rcompare","satisfies","build","SANITY_CACHE_DIR","createExternalFromImportMap","VENDOR_DIR","VENDOR_IMPORTS","react","STYLED_COMPONENTS_IMPORTS","buildVendorDependencies","basePath","cwd","isApp","outputDir","entry","imports","vendorImports","packageName","ranges","Object","entries","version","Error","sortedRanges","keys","toSorted","range1","range2","min1","min2","matchedRange","find","range","min","at","subpaths","packageDir","subpath","relativeEntryPoint","specifier","posix","join","chunkName","relative","buildResult","appType","commonjsOptions","strictRequires","emptyOutDir","lib","formats","minify","outDir","rollupOptions","external","output","chunkFileNames","entryFileNames","exports","format","treeshake","preset","cacheDir","configFile","define","JSON","stringify","logLevel","mode","root","Array","isArray","hashedImports","flatMap","i","chunk","type","originalPath","endsWith","name","fileName"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/build/buildVendorDependencies.ts"],"sourcesContent":["import {readFile} from 'node:fs/promises'\nimport path from 'node:path'\n\nimport {getLocalPackageDir, getLocalPackageVersion} from '@sanity/cli-core'\nimport {gt, minVersion, rcompare, satisfies} from 'semver'\nimport {build, esmExternalRequirePlugin} from 'vite'\n\nimport {SANITY_CACHE_DIR} from '../../constants.js'\nimport {createExternalFromImportMap} from './createExternalFromImportMap.js'\nimport {getCjsNamedExports} from './getCjsNamedExports.js'\nimport {createVendorNamedExportsPlugin} from './vite/plugin-sanity-vendor-named-exports.js'\n\n// Directory where vendor packages will be stored\nconst VENDOR_DIR = 'vendor'\n\n/**\n * A type representing the imports of vendor packages, defining specific entry\n * points for various versions and subpaths of the packages.\n *\n * The `VendorImports` object is used to build ESM browser-compatible versions\n * of the specified packages. This approach ensures that the appropriate version\n * and entry points are used for each package, enabling compatibility and proper\n * functionality in the browser environment.\n *\n * ## Rationale\n *\n * The rationale for this structure is to handle different versions of the\n * packages carefully, especially major versions. Major version bumps often\n * introduce breaking changes, so the module scheme for the package needs to be\n * checked when there is a major version update. However, minor and patch\n * versions are generally backward compatible, so they are handled more\n * leniently. By assuming that new minor versions are compatible, we avoid\n * unnecessary warnings and streamline the update process.\n *\n * If a new minor version introduces an additional subpath export within the\n * package of this version range, the corresponding package can add a more\n * specific version range that includes the new subpath. This design allows for\n * flexibility and ease of maintenance, ensuring that the latest features and\n * fixes are incorporated without extensive manual intervention.\n *\n * An additional subpath export within the package of this version range that\n * could cause the build to break if that new export is used, can be treated as\n * a bug fix. It might make more sense to our users that this new subpath isn't\n * supported yet until we address it as a bug fix. This approach helps maintain\n * stability and prevents unexpected issues during the build process.\n *\n * ## Structure\n * The `VendorImports` type is a nested object where:\n * - The keys at the first level represent the package names.\n * - The keys at the second level represent the version ranges (e.g., `^19.0.0`).\n * - The keys at the third level represent the subpaths within the package (e.g., `.` for the main entry point).\n * - The values at the third level are the relative paths to the corresponding entry points within the package.\n *\n * This structure allows for precise specification of the entry points for\n * different versions and subpaths, ensuring that the correct files are used\n * during the build process.\n */\ntype VendorImports = {\n [packageName: string]: {\n [versionRange: string]: {\n [subpath: string]: string\n }\n }\n}\n\n// Define the vendor packages and their corresponding versions and entry points\nconst VENDOR_IMPORTS: VendorImports = {\n react: {\n '^19.2.0': {\n '.': './cjs/react.production.js',\n './compiler-runtime': './cjs/react-compiler-runtime.production.js',\n './jsx-dev-runtime': './cjs/react-jsx-dev-runtime.production.js',\n './jsx-runtime': './cjs/react-jsx-runtime.production.js',\n './package.json': './package.json',\n },\n },\n 'react-dom': {\n '^19.2.0': {\n '.': './cjs/react-dom.production.js',\n './client': './cjs/react-dom-client.production.js',\n './package.json': './package.json',\n './server': './cjs/react-dom-server-legacy.browser.production.js',\n './server.browser': './cjs/react-dom-server-legacy.browser.production.js',\n './static': './cjs/react-dom-server.browser.production.js',\n './static.browser': './cjs/react-dom-server.browser.production.js',\n },\n },\n}\n\nconst STYLED_COMPONENTS_IMPORTS = {\n 'styled-components': {\n '^6.1.0': {\n '.': './dist/styled-components.browser.esm.js',\n './package.json': './package.json',\n },\n },\n}\n\ninterface VendorBuildOptions {\n basePath: string\n cwd: string\n isApp: boolean\n outputDir: string\n}\n\n/**\n * Builds the ESM browser compatible versions of the vendor packages\n * specified in VENDOR_IMPORTS. Returns the `imports` object of an import map.\n */\nexport async function buildVendorDependencies({\n basePath,\n cwd,\n isApp,\n outputDir,\n}: VendorBuildOptions): Promise<Record<string, string>> {\n const entry: Record<string, string> = {}\n const imports: Record<string, string> = {}\n\n // Named exports each CommonJS entry must re-expose as ESM, keyed by chunk name.\n const namesByChunkName: Record<string, readonly string[]> = {}\n\n // If we're building an app, we don't need to build the styled-components package\n const vendorImports = isApp ? VENDOR_IMPORTS : {...VENDOR_IMPORTS, ...STYLED_COMPONENTS_IMPORTS}\n\n // Iterate over each package and its version ranges in VENDOR_IMPORTS\n for (const [packageName, ranges] of Object.entries(vendorImports)) {\n const version = await getLocalPackageVersion(packageName, cwd)\n if (!version) {\n throw new Error(`Could not get version for '${packageName}'`)\n }\n\n // Sort version ranges in descending order\n const sortedRanges = Object.keys(ranges).toSorted((range1, range2) => {\n const min1 = minVersion(range1)\n const min2 = minVersion(range2)\n\n if (!min1) throw new Error(`Could not parse range '${range1}'`)\n if (!min2) throw new Error(`Could not parse range '${range2}'`)\n\n // sort them in reverse so we can rely on array `.find` below\n return rcompare(min1.version, min2.version)\n })\n\n // Find the first version range that satisfies the package version\n const matchedRange = sortedRanges.find((range) => satisfies(version, range))\n\n if (!matchedRange) {\n const min = minVersion(sortedRanges.at(-1)!)\n if (!min) {\n throw new Error(`Could not find a minimum version for package '${packageName}'`)\n }\n\n if (gt(min.version, version)) {\n throw new Error(`Package '${packageName}' requires at least ${min.version}.`)\n }\n\n throw new Error(`Version '${version}' of package '${packageName}' is not supported yet.`)\n }\n\n const subpaths = ranges[matchedRange]\n\n // Resolve the actual package directory using Node module resolution,\n // so that hoisted packages in monorepos/workspaces are found correctly\n const packageDir = getLocalPackageDir(packageName, cwd)\n\n // Iterate over each subpath and its corresponding entry point\n for (const [subpath, relativeEntryPoint] of Object.entries(subpaths)) {\n const specifier = path.posix.join(packageName, subpath)\n const chunkName = path.posix.join(\n packageName,\n path.relative(packageName, specifier) || 'index',\n )\n\n const entryPath = path.join(packageDir, relativeEntryPoint)\n entry[chunkName] = entryPath\n imports[specifier] = path.posix.join('/', basePath, VENDOR_DIR, `${chunkName}.mjs`)\n\n // React and React-DOM ship CommonJS. Rolldown lowers a CJS entry to an ESM\n // chunk that only emits `export default`, so collect the named exports it\n // must additionally re-expose (see `createVendorNamedExportsPlugin`).\n // `styled-components` is native ESM and `package.json` is JSON, so both are\n // skipped here.\n if (packageName in VENDOR_IMPORTS && subpath !== './package.json') {\n const source = await readFile(entryPath, 'utf8')\n namesByChunkName[chunkName] = await getCjsNamedExports(source, chunkName)\n }\n }\n }\n\n // Externals are handled by `esmExternalRequirePlugin` (below) rather than\n // `rolldownOptions.external`: the plugin both marks them external AND rewrites\n // CommonJS `require('react')` calls (e.g. in react-dom) into ESM imports.\n // Also setting `rolldownOptions.external` short-circuits that rewrite, leaving a\n // runtime `require` shim that throws in the browser.\n const external = createExternalFromImportMap({imports})\n\n // removes the `RolldownWatcher` type\n type BuildResult = Exclude<Awaited<ReturnType<typeof build>>, {close: unknown}>\n\n // Use Vite to build the packages into the output directory\n let buildResult = (await build({\n appType: 'custom',\n build: {\n emptyOutDir: false, // Rely on CLI to do this\n lib: {entry, formats: ['es']},\n minify: true,\n outDir: path.join(outputDir, VENDOR_DIR),\n rolldownOptions: {\n // Expose Rolldown's native MagicString on `renderChunk`'s `meta` so the\n // vendor named-exports plugin can edit chunks without a JS dependency.\n experimental: {nativeMagicString: true},\n output: {\n chunkFileNames: '[name]-[hash].mjs',\n entryFileNames: '[name]-[hash].mjs',\n exports: 'named',\n format: 'es',\n },\n treeshake: true,\n },\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-vendor`,\n configFile: false,\n define: {'process.env.NODE_ENV': JSON.stringify('production')},\n logLevel: 'silent',\n mode: 'production',\n plugins: [\n // Re-expose CommonJS named exports (react, react-dom) as real ESM exports;\n // Rolldown only emits `export default` for a CommonJS entry.\n createVendorNamedExportsPlugin(namesByChunkName),\n // Rewrite external `require(...)` (e.g. react-dom requiring react) into ESM\n // imports so the vendored output runs in the browser without `require`.\n esmExternalRequirePlugin({external}),\n ],\n root: cwd,\n })) as BuildResult\n\n buildResult = Array.isArray(buildResult) ? buildResult : [buildResult]\n\n // Create a map of the original import specifiers to their hashed filenames\n const hashedImports: Record<string, string> = {}\n const output = buildResult.flatMap((i) => i.output)\n\n for (const chunk of output) {\n if (chunk.type === 'asset') continue\n\n for (const [specifier, originalPath] of Object.entries(imports)) {\n if (originalPath.endsWith(`${chunk.name}.mjs`)) {\n hashedImports[specifier] = path.posix.join('/', basePath, VENDOR_DIR, chunk.fileName)\n }\n }\n }\n\n return hashedImports\n}\n"],"names":["readFile","path","getLocalPackageDir","getLocalPackageVersion","gt","minVersion","rcompare","satisfies","build","esmExternalRequirePlugin","SANITY_CACHE_DIR","createExternalFromImportMap","getCjsNamedExports","createVendorNamedExportsPlugin","VENDOR_DIR","VENDOR_IMPORTS","react","STYLED_COMPONENTS_IMPORTS","buildVendorDependencies","basePath","cwd","isApp","outputDir","entry","imports","namesByChunkName","vendorImports","packageName","ranges","Object","entries","version","Error","sortedRanges","keys","toSorted","range1","range2","min1","min2","matchedRange","find","range","min","at","subpaths","packageDir","subpath","relativeEntryPoint","specifier","posix","join","chunkName","relative","entryPath","source","external","buildResult","appType","emptyOutDir","lib","formats","minify","outDir","rolldownOptions","experimental","nativeMagicString","output","chunkFileNames","entryFileNames","exports","format","treeshake","cacheDir","configFile","define","JSON","stringify","logLevel","mode","plugins","root","Array","isArray","hashedImports","flatMap","i","chunk","type","originalPath","endsWith","name","fileName"],"mappings":"AAAA,SAAQA,QAAQ,QAAO,mBAAkB;AACzC,OAAOC,UAAU,YAAW;AAE5B,SAAQC,kBAAkB,EAAEC,sBAAsB,QAAO,mBAAkB;AAC3E,SAAQC,EAAE,EAAEC,UAAU,EAAEC,QAAQ,EAAEC,SAAS,QAAO,SAAQ;AAC1D,SAAQC,KAAK,EAAEC,wBAAwB,QAAO,OAAM;AAEpD,SAAQC,gBAAgB,QAAO,qBAAoB;AACnD,SAAQC,2BAA2B,QAAO,mCAAkC;AAC5E,SAAQC,kBAAkB,QAAO,0BAAyB;AAC1D,SAAQC,8BAA8B,QAAO,+CAA8C;AAE3F,iDAAiD;AACjD,MAAMC,aAAa;AAoDnB,+EAA+E;AAC/E,MAAMC,iBAAgC;IACpCC,OAAO;QACL,WAAW;YACT,KAAK;YACL,sBAAsB;YACtB,qBAAqB;YACrB,iBAAiB;YACjB,kBAAkB;QACpB;IACF;IACA,aAAa;QACX,WAAW;YACT,KAAK;YACL,YAAY;YACZ,kBAAkB;YAClB,YAAY;YACZ,oBAAoB;YACpB,YAAY;YACZ,oBAAoB;QACtB;IACF;AACF;AAEA,MAAMC,4BAA4B;IAChC,qBAAqB;QACnB,UAAU;YACR,KAAK;YACL,kBAAkB;QACpB;IACF;AACF;AASA;;;CAGC,GACD,OAAO,eAAeC,wBAAwB,EAC5CC,QAAQ,EACRC,GAAG,EACHC,KAAK,EACLC,SAAS,EACU;IACnB,MAAMC,QAAgC,CAAC;IACvC,MAAMC,UAAkC,CAAC;IAEzC,gFAAgF;IAChF,MAAMC,mBAAsD,CAAC;IAE7D,iFAAiF;IACjF,MAAMC,gBAAgBL,QAAQN,iBAAiB;QAAC,GAAGA,cAAc;QAAE,GAAGE,yBAAyB;IAAA;IAE/F,qEAAqE;IACrE,KAAK,MAAM,CAACU,aAAaC,OAAO,IAAIC,OAAOC,OAAO,CAACJ,eAAgB;QACjE,MAAMK,UAAU,MAAM5B,uBAAuBwB,aAAaP;QAC1D,IAAI,CAACW,SAAS;YACZ,MAAM,IAAIC,MAAM,CAAC,2BAA2B,EAAEL,YAAY,CAAC,CAAC;QAC9D;QAEA,0CAA0C;QAC1C,MAAMM,eAAeJ,OAAOK,IAAI,CAACN,QAAQO,QAAQ,CAAC,CAACC,QAAQC;YACzD,MAAMC,OAAOjC,WAAW+B;YACxB,MAAMG,OAAOlC,WAAWgC;YAExB,IAAI,CAACC,MAAM,MAAM,IAAIN,MAAM,CAAC,uBAAuB,EAAEI,OAAO,CAAC,CAAC;YAC9D,IAAI,CAACG,MAAM,MAAM,IAAIP,MAAM,CAAC,uBAAuB,EAAEK,OAAO,CAAC,CAAC;YAE9D,6DAA6D;YAC7D,OAAO/B,SAASgC,KAAKP,OAAO,EAAEQ,KAAKR,OAAO;QAC5C;QAEA,kEAAkE;QAClE,MAAMS,eAAeP,aAAaQ,IAAI,CAAC,CAACC,QAAUnC,UAAUwB,SAASW;QAErE,IAAI,CAACF,cAAc;YACjB,MAAMG,MAAMtC,WAAW4B,aAAaW,EAAE,CAAC,CAAC;YACxC,IAAI,CAACD,KAAK;gBACR,MAAM,IAAIX,MAAM,CAAC,8CAA8C,EAAEL,YAAY,CAAC,CAAC;YACjF;YAEA,IAAIvB,GAAGuC,IAAIZ,OAAO,EAAEA,UAAU;gBAC5B,MAAM,IAAIC,MAAM,CAAC,SAAS,EAAEL,YAAY,oBAAoB,EAAEgB,IAAIZ,OAAO,CAAC,CAAC,CAAC;YAC9E;YAEA,MAAM,IAAIC,MAAM,CAAC,SAAS,EAAED,QAAQ,cAAc,EAAEJ,YAAY,uBAAuB,CAAC;QAC1F;QAEA,MAAMkB,WAAWjB,MAAM,CAACY,aAAa;QAErC,qEAAqE;QACrE,uEAAuE;QACvE,MAAMM,aAAa5C,mBAAmByB,aAAaP;QAEnD,8DAA8D;QAC9D,KAAK,MAAM,CAAC2B,SAASC,mBAAmB,IAAInB,OAAOC,OAAO,CAACe,UAAW;YACpE,MAAMI,YAAYhD,KAAKiD,KAAK,CAACC,IAAI,CAACxB,aAAaoB;YAC/C,MAAMK,YAAYnD,KAAKiD,KAAK,CAACC,IAAI,CAC/BxB,aACA1B,KAAKoD,QAAQ,CAAC1B,aAAasB,cAAc;YAG3C,MAAMK,YAAYrD,KAAKkD,IAAI,CAACL,YAAYE;YACxCzB,KAAK,CAAC6B,UAAU,GAAGE;YACnB9B,OAAO,CAACyB,UAAU,GAAGhD,KAAKiD,KAAK,CAACC,IAAI,CAAC,KAAKhC,UAAUL,YAAY,GAAGsC,UAAU,IAAI,CAAC;YAElF,2EAA2E;YAC3E,0EAA0E;YAC1E,sEAAsE;YACtE,4EAA4E;YAC5E,gBAAgB;YAChB,IAAIzB,eAAeZ,kBAAkBgC,YAAY,kBAAkB;gBACjE,MAAMQ,SAAS,MAAMvD,SAASsD,WAAW;gBACzC7B,gBAAgB,CAAC2B,UAAU,GAAG,MAAMxC,mBAAmB2C,QAAQH;YACjE;QACF;IACF;IAEA,0EAA0E;IAC1E,+EAA+E;IAC/E,0EAA0E;IAC1E,iFAAiF;IACjF,qDAAqD;IACrD,MAAMI,WAAW7C,4BAA4B;QAACa;IAAO;IAKrD,2DAA2D;IAC3D,IAAIiC,cAAe,MAAMjD,MAAM;QAC7BkD,SAAS;QACTlD,OAAO;YACLmD,aAAa;YACbC,KAAK;gBAACrC;gBAAOsC,SAAS;oBAAC;iBAAK;YAAA;YAC5BC,QAAQ;YACRC,QAAQ9D,KAAKkD,IAAI,CAAC7B,WAAWR;YAC7BkD,iBAAiB;gBACf,wEAAwE;gBACxE,uEAAuE;gBACvEC,cAAc;oBAACC,mBAAmB;gBAAI;gBACtCC,QAAQ;oBACNC,gBAAgB;oBAChBC,gBAAgB;oBAChBC,SAAS;oBACTC,QAAQ;gBACV;gBACAC,WAAW;YACb;QACF;QACA,8DAA8D;QAC9D,2DAA2D;QAC3DC,UAAU,GAAG/D,iBAAiB,YAAY,CAAC;QAC3CgE,YAAY;QACZC,QAAQ;YAAC,wBAAwBC,KAAKC,SAAS,CAAC;QAAa;QAC7DC,UAAU;QACVC,MAAM;QACNC,SAAS;YACP,2EAA2E;YAC3E,6DAA6D;YAC7DnE,+BAA+BY;YAC/B,4EAA4E;YAC5E,wEAAwE;YACxEhB,yBAAyB;gBAAC+C;YAAQ;SACnC;QACDyB,MAAM7D;IACR;IAEAqC,cAAcyB,MAAMC,OAAO,CAAC1B,eAAeA,cAAc;QAACA;KAAY;IAEtE,2EAA2E;IAC3E,MAAM2B,gBAAwC,CAAC;IAC/C,MAAMjB,SAASV,YAAY4B,OAAO,CAAC,CAACC,IAAMA,EAAEnB,MAAM;IAElD,KAAK,MAAMoB,SAASpB,OAAQ;QAC1B,IAAIoB,MAAMC,IAAI,KAAK,SAAS;QAE5B,KAAK,MAAM,CAACvC,WAAWwC,aAAa,IAAI5D,OAAOC,OAAO,CAACN,SAAU;YAC/D,IAAIiE,aAAaC,QAAQ,CAAC,GAAGH,MAAMI,IAAI,CAAC,IAAI,CAAC,GAAG;gBAC9CP,aAAa,CAACnC,UAAU,GAAGhD,KAAKiD,KAAK,CAACC,IAAI,CAAC,KAAKhC,UAAUL,YAAYyE,MAAMK,QAAQ;YACtF;QACF;IACF;IAEA,OAAOR;AACT"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import escapeRegExp from 'lodash-es/escapeRegExp.js';
|
|
2
2
|
/**
|
|
3
|
-
* Generates a
|
|
3
|
+
* Generates a Rolldown `external` configuration array based on the provided
|
|
4
4
|
* import map. We derive externals from the import map because this ensures that
|
|
5
|
-
* modules listed in the import map are not bundled into the
|
|
5
|
+
* modules listed in the import map are not bundled into the Rolldown output so
|
|
6
6
|
* the browser can load these bare specifiers according to the import map.
|
|
7
7
|
*/ export function createExternalFromImportMap({ imports = {} } = {}) {
|
|
8
8
|
return Object.keys(imports).map((specifier)=>specifier.endsWith('/') ? new RegExp(`^${escapeRegExp(specifier)}.+`) : specifier);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/build/createExternalFromImportMap.ts"],"sourcesContent":["import escapeRegExp from 'lodash-es/escapeRegExp.js'\n\ntype ImportMap = {imports?: Record<string, string>}\n\n/**\n * Generates a
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/build/createExternalFromImportMap.ts"],"sourcesContent":["import escapeRegExp from 'lodash-es/escapeRegExp.js'\n\ntype ImportMap = {imports?: Record<string, string>}\n\n/**\n * Generates a Rolldown `external` configuration array based on the provided\n * import map. We derive externals from the import map because this ensures that\n * modules listed in the import map are not bundled into the Rolldown output so\n * the browser can load these bare specifiers according to the import map.\n */\nexport function createExternalFromImportMap({imports = {}}: ImportMap = {}): (RegExp | string)[] {\n return Object.keys(imports).map((specifier) =>\n specifier.endsWith('/') ? new RegExp(`^${escapeRegExp(specifier)}.+`) : specifier,\n )\n}\n"],"names":["escapeRegExp","createExternalFromImportMap","imports","Object","keys","map","specifier","endsWith","RegExp"],"mappings":"AAAA,OAAOA,kBAAkB,4BAA2B;AAIpD;;;;;CAKC,GACD,OAAO,SAASC,4BAA4B,EAACC,UAAU,CAAC,CAAC,EAAY,GAAG,CAAC,CAAC;IACxE,OAAOC,OAAOC,IAAI,CAACF,SAASG,GAAG,CAAC,CAACC,YAC/BA,UAAUC,QAAQ,CAAC,OAAO,IAAIC,OAAO,CAAC,CAAC,EAAER,aAAaM,WAAW,EAAE,CAAC,IAAIA;AAE5E"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// eslint-disable-next-line import-x/no-unresolved
|
|
2
|
+
import { init, parse } from 'cjs-module-lexer';
|
|
3
|
+
/** Memoizes the (Wasm) lexer initialization across calls. */ let lexerReady;
|
|
4
|
+
/**
|
|
5
|
+
* Matches a string that can be used both as `export const <name>` and
|
|
6
|
+
* `import {<name>}`. Names that fail this (reserved words, string-literal export
|
|
7
|
+
* names) are not importable by name, so they are safely skipped.
|
|
8
|
+
*/ const VALID_IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
9
|
+
/**
|
|
10
|
+
* Statically extracts the named exports of a CommonJS module source, without
|
|
11
|
+
* executing it, using `cjs-module-lexer` (the same detector Node.js core uses
|
|
12
|
+
* to expose CommonJS named exports to ESM importers).
|
|
13
|
+
*
|
|
14
|
+
* The vendor build uses this to learn which named bindings each CommonJS entry
|
|
15
|
+
* must re-expose as real ESM exports once Rolldown has lowered it to ESM (see
|
|
16
|
+
* `createVendorNamedExportsPlugin`). Executing the module is intentionally
|
|
17
|
+
* avoided so that bundles which touch DOM globals at evaluation time (e.g.
|
|
18
|
+
* `react-dom`) cannot break the build.
|
|
19
|
+
*
|
|
20
|
+
* @param source - The CommonJS module source code.
|
|
21
|
+
* @param label - Identifier used in error messages (e.g. the chunk name).
|
|
22
|
+
* @returns De-duplicated, importable identifier names, excluding `default` and
|
|
23
|
+
* `__esModule`.
|
|
24
|
+
* @throws If the module re-exports another module (`module.exports = require(...)`);
|
|
25
|
+
* transitive re-export resolution is not supported by the vendor build.
|
|
26
|
+
* @internal
|
|
27
|
+
*/ export async function getCjsNamedExports(source, label) {
|
|
28
|
+
lexerReady ??= init();
|
|
29
|
+
await lexerReady;
|
|
30
|
+
const { exports, reexports } = parse(source);
|
|
31
|
+
if (reexports.length > 0) {
|
|
32
|
+
throw new Error(`Unexpected CommonJS re-exports in '${label}': ${reexports.join(', ')}. ` + `Transitive re-export resolution is not supported by the vendor build.`);
|
|
33
|
+
}
|
|
34
|
+
return [
|
|
35
|
+
...new Set(exports)
|
|
36
|
+
].filter((name)=>name !== 'default' && name !== '__esModule' && VALID_IDENTIFIER.test(name));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
//# sourceMappingURL=getCjsNamedExports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/build/getCjsNamedExports.ts"],"sourcesContent":["// eslint-disable-next-line import-x/no-unresolved\nimport {init, parse} from 'cjs-module-lexer'\n\n/** Memoizes the (Wasm) lexer initialization across calls. */\nlet lexerReady: Promise<void> | undefined\n\n/**\n * Matches a string that can be used both as `export const <name>` and\n * `import {<name>}`. Names that fail this (reserved words, string-literal export\n * names) are not importable by name, so they are safely skipped.\n */\nconst VALID_IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/\n\n/**\n * Statically extracts the named exports of a CommonJS module source, without\n * executing it, using `cjs-module-lexer` (the same detector Node.js core uses\n * to expose CommonJS named exports to ESM importers).\n *\n * The vendor build uses this to learn which named bindings each CommonJS entry\n * must re-expose as real ESM exports once Rolldown has lowered it to ESM (see\n * `createVendorNamedExportsPlugin`). Executing the module is intentionally\n * avoided so that bundles which touch DOM globals at evaluation time (e.g.\n * `react-dom`) cannot break the build.\n *\n * @param source - The CommonJS module source code.\n * @param label - Identifier used in error messages (e.g. the chunk name).\n * @returns De-duplicated, importable identifier names, excluding `default` and\n * `__esModule`.\n * @throws If the module re-exports another module (`module.exports = require(...)`);\n * transitive re-export resolution is not supported by the vendor build.\n * @internal\n */\nexport async function getCjsNamedExports(source: string, label: string): Promise<string[]> {\n lexerReady ??= init()\n await lexerReady\n\n const {exports, reexports} = parse(source)\n\n if (reexports.length > 0) {\n throw new Error(\n `Unexpected CommonJS re-exports in '${label}': ${reexports.join(', ')}. ` +\n `Transitive re-export resolution is not supported by the vendor build.`,\n )\n }\n\n return [...new Set(exports)].filter(\n (name) => name !== 'default' && name !== '__esModule' && VALID_IDENTIFIER.test(name),\n )\n}\n"],"names":["init","parse","lexerReady","VALID_IDENTIFIER","getCjsNamedExports","source","label","exports","reexports","length","Error","join","Set","filter","name","test"],"mappings":"AAAA,kDAAkD;AAClD,SAAQA,IAAI,EAAEC,KAAK,QAAO,mBAAkB;AAE5C,2DAA2D,GAC3D,IAAIC;AAEJ;;;;CAIC,GACD,MAAMC,mBAAmB;AAEzB;;;;;;;;;;;;;;;;;;CAkBC,GACD,OAAO,eAAeC,mBAAmBC,MAAc,EAAEC,KAAa;IACpEJ,eAAeF;IACf,MAAME;IAEN,MAAM,EAACK,OAAO,EAAEC,SAAS,EAAC,GAAGP,MAAMI;IAEnC,IAAIG,UAAUC,MAAM,GAAG,GAAG;QACxB,MAAM,IAAIC,MACR,CAAC,mCAAmC,EAAEJ,MAAM,GAAG,EAAEE,UAAUG,IAAI,CAAC,MAAM,EAAE,CAAC,GACvE,CAAC,qEAAqE,CAAC;IAE7E;IAEA,OAAO;WAAI,IAAIC,IAAIL;KAAS,CAACM,MAAM,CACjC,CAACC,OAASA,SAAS,aAAaA,SAAS,gBAAgBX,iBAAiBY,IAAI,CAACD;AAEnF"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
+
import babel from '@rolldown/plugin-babel';
|
|
2
3
|
import { findProjectRoot, getCliTelemetry } from '@sanity/cli-core';
|
|
3
|
-
import viteReact from '@vitejs/plugin-react';
|
|
4
|
+
import viteReact, { reactCompilerPreset } from '@vitejs/plugin-react';
|
|
4
5
|
import debug from 'debug';
|
|
5
|
-
import { mergeConfig } from 'vite';
|
|
6
|
+
import { esmExternalRequirePlugin, mergeConfig } from 'vite';
|
|
6
7
|
import { SANITY_CACHE_DIR } from '../../constants.js';
|
|
7
8
|
import { sanitySchemaExtractionPlugin } from '../schema/vite/plugin-schema-extraction.js';
|
|
8
9
|
import { createExternalFromImportMap } from './createExternalFromImportMap.js';
|
|
@@ -54,19 +55,14 @@ import { getDefaultFaviconsPath } from './writeFavicons.js';
|
|
|
54
55
|
logLevel: mode === 'production' ? 'silent' : 'info',
|
|
55
56
|
mode,
|
|
56
57
|
plugins: [
|
|
57
|
-
viteReact(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
plugins: [
|
|
63
|
-
[
|
|
64
|
-
'babel-plugin-react-compiler',
|
|
65
|
-
reactCompiler
|
|
66
|
-
]
|
|
58
|
+
...viteReact(),
|
|
59
|
+
...reactCompiler ? [
|
|
60
|
+
babel({
|
|
61
|
+
presets: [
|
|
62
|
+
reactCompilerPreset(reactCompiler)
|
|
67
63
|
]
|
|
68
|
-
}
|
|
69
|
-
|
|
64
|
+
})
|
|
65
|
+
] : [],
|
|
70
66
|
sanityFaviconsPlugin({
|
|
71
67
|
customFaviconsPath,
|
|
72
68
|
defaultFaviconsPath,
|
|
@@ -100,7 +96,9 @@ import { getDefaultFaviconsPath } from './writeFavicons.js';
|
|
|
100
96
|
'react-dom',
|
|
101
97
|
'sanity',
|
|
102
98
|
'styled-components'
|
|
103
|
-
]
|
|
99
|
+
],
|
|
100
|
+
// Honor the studio's tsconfig `paths`, consistent with studioWorkerLoader.worker.ts.
|
|
101
|
+
tsconfigPaths: true
|
|
104
102
|
},
|
|
105
103
|
root: cwd,
|
|
106
104
|
server: {
|
|
@@ -123,23 +121,33 @@ import { getDefaultFaviconsPath } from './writeFavicons.js';
|
|
|
123
121
|
}
|
|
124
122
|
};
|
|
125
123
|
if (mode === 'production') {
|
|
124
|
+
// For auto-updating studios the import map externalizes react/react-dom/etc.
|
|
125
|
+
// Hand those externals to `esmExternalRequirePlugin` rather than
|
|
126
|
+
// `rolldownOptions.external`, so any bundled CommonJS `require()` of an external
|
|
127
|
+
// is rewritten to an ESM import instead of a runtime `require` shim that throws
|
|
128
|
+
// in the browser. The plugin both marks them external AND converts the requires;
|
|
129
|
+
// also setting `rolldownOptions.external` would short-circuit that conversion.
|
|
130
|
+
// With no import map (auto-updates off) the external list is empty and this is a
|
|
131
|
+
// no-op (everything is bundled, so requires resolve internally).
|
|
132
|
+
viteConfig.plugins.push(esmExternalRequirePlugin({
|
|
133
|
+
external: createExternalFromImportMap(importMap)
|
|
134
|
+
}));
|
|
126
135
|
viteConfig.build = {
|
|
127
136
|
...viteConfig.build,
|
|
128
137
|
assetsDir: 'static',
|
|
129
138
|
emptyOutDir: false,
|
|
130
|
-
minify: minify ? '
|
|
131
|
-
|
|
132
|
-
external: createExternalFromImportMap(importMap),
|
|
139
|
+
minify: minify ? 'oxc' : false,
|
|
140
|
+
rolldownOptions: {
|
|
133
141
|
input: {
|
|
134
142
|
sanity: path.join(cwd, '.sanity', 'runtime', 'app.js')
|
|
135
143
|
},
|
|
136
|
-
onwarn:
|
|
144
|
+
onwarn: onRolldownWarn
|
|
137
145
|
}
|
|
138
146
|
};
|
|
139
147
|
}
|
|
140
148
|
return viteConfig;
|
|
141
149
|
}
|
|
142
|
-
function
|
|
150
|
+
function onRolldownWarn(warning, warn) {
|
|
143
151
|
if (suppressUnusedImport(warning)) {
|
|
144
152
|
return;
|
|
145
153
|
}
|
|
@@ -166,15 +174,15 @@ function suppressUnusedImport(warning) {
|
|
|
166
174
|
* @returns Merged configuration
|
|
167
175
|
* @internal
|
|
168
176
|
*/ export async function finalizeViteConfig(config) {
|
|
169
|
-
if (typeof config.build?.
|
|
170
|
-
throw new TypeError('Vite config must contain `build.
|
|
177
|
+
if (typeof config.build?.rolldownOptions?.input !== 'object') {
|
|
178
|
+
throw new TypeError('Vite config must contain `build.rolldownOptions.input`, and it must be an object');
|
|
171
179
|
}
|
|
172
180
|
if (!config.root) {
|
|
173
181
|
throw new Error('Vite config must contain `root` property, and must point to the Sanity root directory');
|
|
174
182
|
}
|
|
175
183
|
return mergeConfig(config, {
|
|
176
184
|
build: {
|
|
177
|
-
|
|
185
|
+
rolldownOptions: {
|
|
178
186
|
input: {
|
|
179
187
|
sanity: path.join(config.root, '.sanity', 'runtime', 'app.js')
|
|
180
188
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/build/getViteConfig.ts"],"sourcesContent":["import path from 'node:path'\n\nimport {\n type CliConfig,\n findProjectRoot,\n getCliTelemetry,\n type UserViteConfig,\n} from '@sanity/cli-core'\nimport viteReact from '@vitejs/plugin-react'\nimport {type PluginOptions as ReactCompilerConfig} from 'babel-plugin-react-compiler'\nimport debug from 'debug'\nimport {type ConfigEnv, type InlineConfig, mergeConfig, type Plugin, type Rollup} from 'vite'\n\nimport {SANITY_CACHE_DIR} from '../../constants.js'\nimport {sanitySchemaExtractionPlugin} from '../schema/vite/plugin-schema-extraction.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 {getDefaultFaviconsPath} from './writeFavicons.js'\n\ninterface ViteOptions {\n /**\n * Root path of the studio/sanity app\n */\n cwd: string\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 * CSS URLs for auto-updated packages (loaded via module server)\n */\n autoUpdatesCssUrls?: string[]\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 importMap?: {imports?: Record<string, string>}\n\n isApp?: 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 * Schema extraction configuration\n */\n schemaExtraction?: CliConfig['schemaExtraction']\n /**\n * HTTP development server configuration\n */\n server?: {host?: string; port?: number}\n /**\n * Whether or not to enable source maps\n */\n sourceMap?: boolean\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 autoUpdatesCssUrls,\n basePath: rawBasePath = '/',\n cwd,\n importMap,\n isApp,\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 } = 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 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 viteReact(\n reactCompiler\n ? {\n babel: {\n generatorOpts: {compact: true},\n plugins: [['babel-plugin-react-compiler', reactCompiler]],\n },\n }\n : {},\n ),\n sanityFaviconsPlugin({customFaviconsPath, defaultFaviconsPath, staticUrlPath: staticPath}),\n sanityRuntimeRewritePlugin(),\n sanityBuildEntries({autoUpdatesCssUrls, basePath, cwd, importMap, isApp}),\n // Add schema extraction when enabled\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 ...(additionalPlugins || []),\n ],\n resolve: {\n dedupe: ['react', 'react-dom', 'sanity', 'styled-components'],\n },\n root: cwd,\n server: {\n host: server?.host,\n port: server?.port || 3333,\n // Only enable strict port for studio,\n // since apps can run on any port\n strictPort: isApp ? false : true,\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 if (mode === 'production') {\n viteConfig.build = {\n ...viteConfig.build,\n\n assetsDir: 'static',\n emptyOutDir: false, // Rely on CLI to do this\n minify: minify ? 'esbuild' : false,\n\n rollupOptions: {\n external: createExternalFromImportMap(importMap),\n input: {\n sanity: path.join(cwd, '.sanity', 'runtime', 'app.js'),\n },\n onwarn: onRollupWarn,\n },\n }\n }\n\n return viteConfig\n}\n\nfunction onRollupWarn(warning: Rollup.RollupLog, warn: Rollup.LoggingFunction) {\n if (suppressUnusedImport(warning)) {\n return\n }\n\n warn(warning)\n}\n\nfunction suppressUnusedImport(warning: Rollup.RollupLog & {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 * Ensure Sanity entry chunk is always loaded\n *\n * @param config - User-modified configuration\n * @returns Merged configuration\n * @internal\n */\nexport async function finalizeViteConfig(config: InlineConfig): Promise<InlineConfig> {\n if (typeof config.build?.rollupOptions?.input !== 'object') {\n throw new TypeError(\n 'Vite config must contain `build.rollupOptions.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 rollupOptions: {\n input: {\n sanity: path.join(config.root, '.sanity', 'runtime', 'app.js'),\n },\n },\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","findProjectRoot","getCliTelemetry","viteReact","debug","mergeConfig","SANITY_CACHE_DIR","sanitySchemaExtractionPlugin","createExternalFromImportMap","normalizeBasePath","sanityBuildEntries","sanityFaviconsPlugin","sanityRuntimeRewritePlugin","getDefaultFaviconsPath","getViteConfig","options","additionalPlugins","autoUpdatesCssUrls","basePath","rawBasePath","cwd","importMap","isApp","minify","mode","outputDir","reactCompiler","schemaExtraction","server","sourceMap","configPath","customFaviconsPath","join","defaultFaviconsPath","staticPath","envVars","getEnvironmentVariables","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","babel","generatorOpts","compact","staticUrlPath","enabled","additionalPatterns","watchPatterns","enforceRequiredFields","outputPath","telemetryLogger","workDir","workspaceName","workspace","dedupe","root","host","port","strictPort","warmup","clientFiles","assetsDir","emptyOutDir","rollupOptions","external","input","sanity","onwarn","onRollupWarn","warning","warn","suppressUnusedImport","code","names","includes","filter","n","length","ids","every","id","finalizeViteConfig","config","TypeError","Error","extendViteConfigWithUserConfig","defaultConfig","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 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 Rolldown,\n} from 'vite'\n\nimport {SANITY_CACHE_DIR} from '../../constants.js'\nimport {sanitySchemaExtractionPlugin} from '../schema/vite/plugin-schema-extraction.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 {getDefaultFaviconsPath} from './writeFavicons.js'\n\ninterface ViteOptions {\n /**\n * Root path of the studio/sanity app\n */\n cwd: string\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 * CSS URLs for auto-updated packages (loaded via module server)\n */\n autoUpdatesCssUrls?: string[]\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 importMap?: {imports?: Record<string, string>}\n\n isApp?: 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 * Schema extraction configuration\n */\n schemaExtraction?: CliConfig['schemaExtraction']\n /**\n * HTTP development server configuration\n */\n server?: {host?: string; port?: number}\n /**\n * Whether or not to enable source maps\n */\n sourceMap?: boolean\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 autoUpdatesCssUrls,\n basePath: rawBasePath = '/',\n cwd,\n importMap,\n isApp,\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 } = 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 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 ...viteReact(),\n ...(reactCompiler ? [babel({presets: [reactCompilerPreset(reactCompiler)]})] : []),\n sanityFaviconsPlugin({customFaviconsPath, defaultFaviconsPath, staticUrlPath: staticPath}),\n sanityRuntimeRewritePlugin(),\n sanityBuildEntries({autoUpdatesCssUrls, basePath, cwd, importMap, isApp}),\n // Add schema extraction when enabled\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 ...(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 // Only enable strict port for studio,\n // since apps can run on any port\n strictPort: isApp ? false : true,\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 if (mode === 'production') {\n // For auto-updating studios the import map externalizes react/react-dom/etc.\n // Hand those externals to `esmExternalRequirePlugin` rather than\n // `rolldownOptions.external`, so any bundled CommonJS `require()` of an external\n // is rewritten to an ESM import instead of a runtime `require` shim that throws\n // in the browser. The plugin both marks them external AND converts the requires;\n // also setting `rolldownOptions.external` would short-circuit that conversion.\n // With no import map (auto-updates off) the external list is empty and this is a\n // no-op (everything is bundled, so requires resolve internally).\n viteConfig.plugins!.push(\n esmExternalRequirePlugin({external: createExternalFromImportMap(importMap)}),\n )\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 },\n onwarn: onRolldownWarn,\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 * Ensure Sanity entry chunk is always loaded\n *\n * @param config - User-modified configuration\n * @returns Merged configuration\n * @internal\n */\nexport async function finalizeViteConfig(config: InlineConfig): 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: {\n input: {\n sanity: path.join(config.root, '.sanity', 'runtime', 'app.js'),\n },\n },\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","viteReact","reactCompilerPreset","debug","esmExternalRequirePlugin","mergeConfig","SANITY_CACHE_DIR","sanitySchemaExtractionPlugin","createExternalFromImportMap","normalizeBasePath","sanityBuildEntries","sanityFaviconsPlugin","sanityRuntimeRewritePlugin","getDefaultFaviconsPath","getViteConfig","options","additionalPlugins","autoUpdatesCssUrls","basePath","rawBasePath","cwd","importMap","isApp","minify","mode","outputDir","reactCompiler","schemaExtraction","server","sourceMap","configPath","customFaviconsPath","join","defaultFaviconsPath","staticPath","envVars","getEnvironmentVariables","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","presets","staticUrlPath","enabled","additionalPatterns","watchPatterns","enforceRequiredFields","outputPath","telemetryLogger","workDir","workspaceName","workspace","dedupe","tsconfigPaths","root","host","port","strictPort","warmup","clientFiles","push","external","assetsDir","emptyOutDir","rolldownOptions","input","sanity","onwarn","onRolldownWarn","warning","warn","suppressUnusedImport","code","names","includes","filter","n","length","ids","every","id","finalizeViteConfig","config","TypeError","Error","extendViteConfigWithUserConfig","defaultConfig","userConfig"],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal subset of the `magic-string` / Rolldown native `RolldownMagicString`
|
|
3
|
+
* API used by {@link injectNamedExports}. Both the JS `magic-string` package and
|
|
4
|
+
* Rolldown's native MagicString satisfy this, so the same logic runs in
|
|
5
|
+
* production (native, via `renderChunk`'s `meta.magicString`) and in unit tests
|
|
6
|
+
* (the JS implementation).
|
|
7
|
+
*/ /** Base name for the local binding that captures the chunk's default export. */ const DEFAULT_LOCAL = '__sanityVendorDefault';
|
|
8
|
+
/** Resolves a `ModuleExportName` (identifier or string-literal) to its string. */ function moduleExportName(node) {
|
|
9
|
+
return node.type === 'Literal' ? String(node.value) : String(node.name);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Picks a local binding name that does not already exist as a word in `code`,
|
|
13
|
+
* suffixing with a counter on the (extremely unlikely) chance of a collision.
|
|
14
|
+
*/ function pickLocalName(code) {
|
|
15
|
+
if (!new RegExp(String.raw`\b${DEFAULT_LOCAL}\b`).test(code)) {
|
|
16
|
+
return DEFAULT_LOCAL;
|
|
17
|
+
}
|
|
18
|
+
let suffix = 2;
|
|
19
|
+
while(new RegExp(String.raw`\b${DEFAULT_LOCAL}${suffix}\b`).test(code)){
|
|
20
|
+
suffix++;
|
|
21
|
+
}
|
|
22
|
+
return `${DEFAULT_LOCAL}${suffix}`;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Rewrites a rendered Rolldown chunk in place so that, alongside its
|
|
26
|
+
* `export default` (the wrapped CommonJS `module.exports`), it also exposes
|
|
27
|
+
* `names` as real ESM named exports.
|
|
28
|
+
*
|
|
29
|
+
* Rolldown lowers a CommonJS entry to an ESM chunk that only emits a default
|
|
30
|
+
* export; it does not synthesize the `exports.foo = ...` assignments as named
|
|
31
|
+
* ESM exports. Since the vendored `.mjs` files are loaded directly by the
|
|
32
|
+
* browser via an import map, a named import such as `useState` from `react` is
|
|
33
|
+
* a live binding lookup that fails without this. We capture the default value
|
|
34
|
+
* into a local binding and append one `export const` per missing name, each
|
|
35
|
+
* reading the matching property off that local.
|
|
36
|
+
*
|
|
37
|
+
* Two emitted default-export shapes are handled: an inline default expression
|
|
38
|
+
* (rewritten to capture it into the local), and a default re-exported from
|
|
39
|
+
* another chunk (imported under the local). Any other shape throws.
|
|
40
|
+
*
|
|
41
|
+
* @throws If the default export cannot be located, or a targeted name cannot be
|
|
42
|
+
* satisfied. Failing loud turns Rolldown codegen drift (e.g. on a Vite bump)
|
|
43
|
+
* into a build error instead of a runtime missing-named-export crash.
|
|
44
|
+
* @internal
|
|
45
|
+
*/ export function injectNamedExports({ chunkName, exports: existingExports, magicString, names, program }) {
|
|
46
|
+
const existing = new Set(existingExports);
|
|
47
|
+
const namesToAdd = names.filter((name)=>!existing.has(name));
|
|
48
|
+
if (namesToAdd.length === 0) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const local = pickLocalName(magicString.toString());
|
|
52
|
+
let inlineDefault;
|
|
53
|
+
let reexportedDefault;
|
|
54
|
+
for (const node of program.body){
|
|
55
|
+
if (node.type === 'ExportDefaultDeclaration') {
|
|
56
|
+
inlineDefault = node;
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
if (node.type === 'ExportNamedDeclaration') {
|
|
60
|
+
const named = node;
|
|
61
|
+
const specifier = named.source ? named.specifiers.find((spec)=>moduleExportName(spec.exported) === 'default') : undefined;
|
|
62
|
+
if (specifier) {
|
|
63
|
+
reexportedDefault = {
|
|
64
|
+
node: named,
|
|
65
|
+
specifier
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const namedExportLines = namesToAdd.map((name)=>`export const ${name} = ${local}.${name}`);
|
|
71
|
+
if (inlineDefault) {
|
|
72
|
+
// Shape A: `export default <expr>;` -> `const <local> = <expr>;`
|
|
73
|
+
magicString.overwrite(inlineDefault.start, inlineDefault.declaration.start, `const ${local} = `);
|
|
74
|
+
magicString.append(`\nexport default ${local}\n${namedExportLines.join('\n')}\n`);
|
|
75
|
+
} else if (reexportedDefault) {
|
|
76
|
+
// Shape B: `export { x as default } from '<source>';` (kept as-is)
|
|
77
|
+
const source = String(reexportedDefault.node.source?.value);
|
|
78
|
+
const imported = moduleExportName(reexportedDefault.specifier.local);
|
|
79
|
+
const importStatement = imported === 'default' ? `import ${local} from ${JSON.stringify(source)}` : `import {${imported} as ${local}} from ${JSON.stringify(source)}`;
|
|
80
|
+
magicString.prepend(`${importStatement}\n`);
|
|
81
|
+
magicString.append(`\n${namedExportLines.join('\n')}\n`);
|
|
82
|
+
} else {
|
|
83
|
+
throw new Error(`[vendor-named-exports] Could not locate the default export of chunk '${chunkName}' ` + `to attach named exports (${namesToAdd.join(', ')}). The Rolldown output shape may have changed.`);
|
|
84
|
+
}
|
|
85
|
+
// Fail loud if any targeted name was not satisfied (existing export or appended).
|
|
86
|
+
const ensured = new Set([
|
|
87
|
+
...existing,
|
|
88
|
+
...namesToAdd
|
|
89
|
+
]);
|
|
90
|
+
const missing = names.filter((name)=>!ensured.has(name));
|
|
91
|
+
if (missing.length > 0) {
|
|
92
|
+
throw new Error(`[vendor-named-exports] Failed to expose named export(s) on chunk '${chunkName}': ${missing.join(', ')}.`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
//# sourceMappingURL=injectNamedExports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/actions/build/vite/injectNamedExports.ts"],"sourcesContent":["/**\n * Minimal subset of the `magic-string` / Rolldown native `RolldownMagicString`\n * API used by {@link injectNamedExports}. Both the JS `magic-string` package and\n * Rolldown's native MagicString satisfy this, so the same logic runs in\n * production (native, via `renderChunk`'s `meta.magicString`) and in unit tests\n * (the JS implementation).\n */\ninterface MagicStringLike {\n append(content: string): unknown\n overwrite(start: number, end: number, content: string): unknown\n prepend(content: string): unknown\n toString(): string\n}\n\n/** A node with source-span offsets (every oxc/ESTree node). */\ninterface SpanNode {\n end: number\n start: number\n type: string\n}\n\n/** `Identifier` (`name`) or string-literal (`value`) module export name. */\ninterface ModuleExportName extends SpanNode {\n name?: string\n value?: string\n}\n\ninterface ExportSpecifierNode extends SpanNode {\n exported: ModuleExportName\n local: ModuleExportName\n type: 'ExportSpecifier'\n}\n\ninterface ExportDefaultDeclarationNode extends SpanNode {\n declaration: SpanNode\n type: 'ExportDefaultDeclaration'\n}\n\ninterface ExportNamedDeclarationNode extends SpanNode {\n source: (SpanNode & {value?: string}) | null\n specifiers: ExportSpecifierNode[]\n type: 'ExportNamedDeclaration'\n}\n\n/**\n * Structural shape of a parsed program, compatible with both `this.parse` (the\n * Rolldown plugin context) and Vite's exported `parseAst`.\n */\ninterface ProgramLike {\n body: ReadonlyArray<SpanNode>\n}\n\ninterface InjectNamedExportsOptions {\n /** Chunk name, used in error messages. */\n chunkName: string\n /** Names already exported by the chunk (`chunk.exports`). */\n exports: readonly string[]\n /** The chunk's MagicString instance, edited in place. */\n magicString: MagicStringLike\n /** Target named exports to ensure exist (from `getCjsNamedExports`). */\n names: readonly string[]\n /** Parsed AST of the chunk code (`this.parse(code)` / `parseAst(code)`). */\n program: ProgramLike\n}\n\n/** Base name for the local binding that captures the chunk's default export. */\nconst DEFAULT_LOCAL = '__sanityVendorDefault'\n\n/** Resolves a `ModuleExportName` (identifier or string-literal) to its string. */\nfunction moduleExportName(node: ModuleExportName): string {\n return node.type === 'Literal' ? String(node.value) : String(node.name)\n}\n\n/**\n * Picks a local binding name that does not already exist as a word in `code`,\n * suffixing with a counter on the (extremely unlikely) chance of a collision.\n */\nfunction pickLocalName(code: string): string {\n if (!new RegExp(String.raw`\\b${DEFAULT_LOCAL}\\b`).test(code)) {\n return DEFAULT_LOCAL\n }\n let suffix = 2\n while (new RegExp(String.raw`\\b${DEFAULT_LOCAL}${suffix}\\b`).test(code)) {\n suffix++\n }\n return `${DEFAULT_LOCAL}${suffix}`\n}\n\n/**\n * Rewrites a rendered Rolldown chunk in place so that, alongside its\n * `export default` (the wrapped CommonJS `module.exports`), it also exposes\n * `names` as real ESM named exports.\n *\n * Rolldown lowers a CommonJS entry to an ESM chunk that only emits a default\n * export; it does not synthesize the `exports.foo = ...` assignments as named\n * ESM exports. Since the vendored `.mjs` files are loaded directly by the\n * browser via an import map, a named import such as `useState` from `react` is\n * a live binding lookup that fails without this. We capture the default value\n * into a local binding and append one `export const` per missing name, each\n * reading the matching property off that local.\n *\n * Two emitted default-export shapes are handled: an inline default expression\n * (rewritten to capture it into the local), and a default re-exported from\n * another chunk (imported under the local). Any other shape throws.\n *\n * @throws If the default export cannot be located, or a targeted name cannot be\n * satisfied. Failing loud turns Rolldown codegen drift (e.g. on a Vite bump)\n * into a build error instead of a runtime missing-named-export crash.\n * @internal\n */\nexport function injectNamedExports({\n chunkName,\n exports: existingExports,\n magicString,\n names,\n program,\n}: InjectNamedExportsOptions): void {\n const existing = new Set(existingExports)\n const namesToAdd = names.filter((name) => !existing.has(name))\n\n if (namesToAdd.length === 0) {\n return\n }\n\n const local = pickLocalName(magicString.toString())\n\n let inlineDefault: ExportDefaultDeclarationNode | undefined\n let reexportedDefault:\n | {node: ExportNamedDeclarationNode; specifier: ExportSpecifierNode}\n | undefined\n\n for (const node of program.body) {\n if (node.type === 'ExportDefaultDeclaration') {\n inlineDefault = node as ExportDefaultDeclarationNode\n break\n }\n\n if (node.type === 'ExportNamedDeclaration') {\n const named = node as ExportNamedDeclarationNode\n const specifier = named.source\n ? named.specifiers.find((spec) => moduleExportName(spec.exported) === 'default')\n : undefined\n if (specifier) {\n reexportedDefault = {node: named, specifier}\n }\n }\n }\n\n const namedExportLines = namesToAdd.map((name) => `export const ${name} = ${local}.${name}`)\n\n if (inlineDefault) {\n // Shape A: `export default <expr>;` -> `const <local> = <expr>;`\n magicString.overwrite(inlineDefault.start, inlineDefault.declaration.start, `const ${local} = `)\n magicString.append(`\\nexport default ${local}\\n${namedExportLines.join('\\n')}\\n`)\n } else if (reexportedDefault) {\n // Shape B: `export { x as default } from '<source>';` (kept as-is)\n const source = String(reexportedDefault.node.source?.value)\n const imported = moduleExportName(reexportedDefault.specifier.local)\n const importStatement =\n imported === 'default'\n ? `import ${local} from ${JSON.stringify(source)}`\n : `import {${imported} as ${local}} from ${JSON.stringify(source)}`\n magicString.prepend(`${importStatement}\\n`)\n magicString.append(`\\n${namedExportLines.join('\\n')}\\n`)\n } else {\n throw new Error(\n `[vendor-named-exports] Could not locate the default export of chunk '${chunkName}' ` +\n `to attach named exports (${namesToAdd.join(', ')}). The Rolldown output shape may have changed.`,\n )\n }\n\n // Fail loud if any targeted name was not satisfied (existing export or appended).\n const ensured = new Set([...existing, ...namesToAdd])\n const missing = names.filter((name) => !ensured.has(name))\n if (missing.length > 0) {\n throw new Error(\n `[vendor-named-exports] Failed to expose named export(s) on chunk '${chunkName}': ${missing.join(', ')}.`,\n )\n }\n}\n"],"names":["DEFAULT_LOCAL","moduleExportName","node","type","String","value","name","pickLocalName","code","RegExp","raw","test","suffix","injectNamedExports","chunkName","exports","existingExports","magicString","names","program","existing","Set","namesToAdd","filter","has","length","local","toString","inlineDefault","reexportedDefault","body","named","specifier","source","specifiers","find","spec","exported","undefined","namedExportLines","map","overwrite","start","declaration","append","join","imported","importStatement","JSON","stringify","prepend","Error","ensured","missing"],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { injectNamedExports } from './injectNamedExports.js';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a Vite (Rolldown) plugin for the vendor build that ensures each
|
|
4
|
+
* emitted CommonJS-derived entry chunk (`react`, `react-dom`, and friends)
|
|
5
|
+
* exposes real ESM named exports in addition to its `export default`.
|
|
6
|
+
*
|
|
7
|
+
* ## Why
|
|
8
|
+
* Vite 8 bundles with Rolldown, which lowers a CommonJS entry to an ESM chunk
|
|
9
|
+
* that only emits a default export (the wrapped `module.exports`); it does not
|
|
10
|
+
* re-emit the `exports.foo = ...` assignments as named ESM exports. The
|
|
11
|
+
* vendored `.mjs` files are loaded directly by the browser via an import map,
|
|
12
|
+
* so a named import such as `useState` from `react` is a live binding lookup
|
|
13
|
+
* that crashes without them.
|
|
14
|
+
*
|
|
15
|
+
* ## Why this approach
|
|
16
|
+
* Vite 8 no longer ships `@rollup/plugin-commonjs` (its `commonjsOptions` are a
|
|
17
|
+
* no-op), and adding it back deadlocks under Rolldown — it relies on
|
|
18
|
+
* `syntheticNamedExports` and `this.load()` in `transform`, which Rolldown does
|
|
19
|
+
* not support. A generated proxy-entry module was the other option; instead we
|
|
20
|
+
* complete the transform on the real emitted chunk: in `renderChunk` we parse
|
|
21
|
+
* the output with `this.parse` and append the named exports using the native
|
|
22
|
+
* MagicString (`meta.magicString`, enabled via `experimental.nativeMagicString`
|
|
23
|
+
* on the vendor build).
|
|
24
|
+
*
|
|
25
|
+
* @param namesByChunkName - Map of entry chunk name (e.g. `react/index`) to the
|
|
26
|
+
* named exports its CommonJS source declares (see `getCjsNamedExports`).
|
|
27
|
+
* @internal
|
|
28
|
+
*/ export function createVendorNamedExportsPlugin(namesByChunkName) {
|
|
29
|
+
return {
|
|
30
|
+
apply: 'build',
|
|
31
|
+
name: 'sanity/vendor-named-exports',
|
|
32
|
+
renderChunk (code, chunk, _outputOptions, meta) {
|
|
33
|
+
const names = chunk.isEntry ? namesByChunkName[chunk.name] : undefined;
|
|
34
|
+
if (!names || names.length === 0) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
const { magicString } = meta;
|
|
38
|
+
if (!magicString) {
|
|
39
|
+
throw new Error(`[vendor-named-exports] Native MagicString unavailable while rendering chunk '${chunk.name}'. ` + `Ensure 'experimental.nativeMagicString' is enabled for the vendor build.`);
|
|
40
|
+
}
|
|
41
|
+
injectNamedExports({
|
|
42
|
+
chunkName: chunk.name,
|
|
43
|
+
exports: chunk.exports,
|
|
44
|
+
magicString,
|
|
45
|
+
names,
|
|
46
|
+
program: this.parse(code)
|
|
47
|
+
});
|
|
48
|
+
return magicString;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
//# sourceMappingURL=plugin-sanity-vendor-named-exports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/actions/build/vite/plugin-sanity-vendor-named-exports.ts"],"sourcesContent":["import {type Plugin} from 'vite'\n\nimport {injectNamedExports} from './injectNamedExports.js'\n\n/**\n * Creates a Vite (Rolldown) plugin for the vendor build that ensures each\n * emitted CommonJS-derived entry chunk (`react`, `react-dom`, and friends)\n * exposes real ESM named exports in addition to its `export default`.\n *\n * ## Why\n * Vite 8 bundles with Rolldown, which lowers a CommonJS entry to an ESM chunk\n * that only emits a default export (the wrapped `module.exports`); it does not\n * re-emit the `exports.foo = ...` assignments as named ESM exports. The\n * vendored `.mjs` files are loaded directly by the browser via an import map,\n * so a named import such as `useState` from `react` is a live binding lookup\n * that crashes without them.\n *\n * ## Why this approach\n * Vite 8 no longer ships `@rollup/plugin-commonjs` (its `commonjsOptions` are a\n * no-op), and adding it back deadlocks under Rolldown — it relies on\n * `syntheticNamedExports` and `this.load()` in `transform`, which Rolldown does\n * not support. A generated proxy-entry module was the other option; instead we\n * complete the transform on the real emitted chunk: in `renderChunk` we parse\n * the output with `this.parse` and append the named exports using the native\n * MagicString (`meta.magicString`, enabled via `experimental.nativeMagicString`\n * on the vendor build).\n *\n * @param namesByChunkName - Map of entry chunk name (e.g. `react/index`) to the\n * named exports its CommonJS source declares (see `getCjsNamedExports`).\n * @internal\n */\nexport function createVendorNamedExportsPlugin(\n namesByChunkName: Record<string, readonly string[]>,\n): Plugin {\n return {\n apply: 'build',\n name: 'sanity/vendor-named-exports',\n\n renderChunk(code, chunk, _outputOptions, meta) {\n const names = chunk.isEntry ? namesByChunkName[chunk.name] : undefined\n if (!names || names.length === 0) {\n return null\n }\n\n const {magicString} = meta\n if (!magicString) {\n throw new Error(\n `[vendor-named-exports] Native MagicString unavailable while rendering chunk '${chunk.name}'. ` +\n `Ensure 'experimental.nativeMagicString' is enabled for the vendor build.`,\n )\n }\n\n injectNamedExports({\n chunkName: chunk.name,\n exports: chunk.exports,\n magicString,\n names,\n program: this.parse(code),\n })\n\n return magicString\n },\n }\n}\n"],"names":["injectNamedExports","createVendorNamedExportsPlugin","namesByChunkName","apply","name","renderChunk","code","chunk","_outputOptions","meta","names","isEntry","undefined","length","magicString","Error","chunkName","exports","program","parse"],"mappings":"AAEA,SAAQA,kBAAkB,QAAO,0BAAyB;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BC,GACD,OAAO,SAASC,+BACdC,gBAAmD;IAEnD,OAAO;QACLC,OAAO;QACPC,MAAM;QAENC,aAAYC,IAAI,EAAEC,KAAK,EAAEC,cAAc,EAAEC,IAAI;YAC3C,MAAMC,QAAQH,MAAMI,OAAO,GAAGT,gBAAgB,CAACK,MAAMH,IAAI,CAAC,GAAGQ;YAC7D,IAAI,CAACF,SAASA,MAAMG,MAAM,KAAK,GAAG;gBAChC,OAAO;YACT;YAEA,MAAM,EAACC,WAAW,EAAC,GAAGL;YACtB,IAAI,CAACK,aAAa;gBAChB,MAAM,IAAIC,MACR,CAAC,6EAA6E,EAAER,MAAMH,IAAI,CAAC,GAAG,CAAC,GAC7F,CAAC,wEAAwE,CAAC;YAEhF;YAEAJ,mBAAmB;gBACjBgB,WAAWT,MAAMH,IAAI;gBACrBa,SAASV,MAAMU,OAAO;gBACtBH;gBACAJ;gBACAQ,SAAS,IAAI,CAACC,KAAK,CAACb;YACtB;YAEA,OAAOQ;QACT;IACF;AACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanity/cli-build",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Internal Sanity package for building studios and apps",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -43,12 +43,14 @@
|
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@oclif/core": "^4.11.4",
|
|
46
|
+
"@rolldown/plugin-babel": "^0.2.3",
|
|
46
47
|
"@sanity/generate-help-url": "^4.0.0",
|
|
47
48
|
"@sanity/schema": "^5.30.0",
|
|
48
49
|
"@sanity/telemetry": "^1.1.0",
|
|
49
50
|
"@sanity/types": "^5.30.0",
|
|
50
|
-
"@vitejs/plugin-react": "^
|
|
51
|
+
"@vitejs/plugin-react": "^6.0.2",
|
|
51
52
|
"chokidar": "^5.0.0",
|
|
53
|
+
"cjs-module-lexer": "^2.2.0",
|
|
52
54
|
"debug": "^4.4.3",
|
|
53
55
|
"lodash-es": "^4.18.1",
|
|
54
56
|
"node-html-parser": "^7.1.0",
|
|
@@ -57,9 +59,9 @@
|
|
|
57
59
|
"react-dom": "^19.2.6",
|
|
58
60
|
"read-package-up": "^12.0.0",
|
|
59
61
|
"semver": "^7.7.4",
|
|
60
|
-
"vite": "^
|
|
62
|
+
"vite": "^8.0.16",
|
|
61
63
|
"zod": "^4.3.6",
|
|
62
|
-
"@sanity/cli-core": "^
|
|
64
|
+
"@sanity/cli-core": "^2.0.0"
|
|
63
65
|
},
|
|
64
66
|
"devDependencies": {
|
|
65
67
|
"@eslint/compat": "^2.0.5",
|
|
@@ -74,17 +76,19 @@
|
|
|
74
76
|
"@types/react": "^19.2.16",
|
|
75
77
|
"@types/react-dom": "^19.2.3",
|
|
76
78
|
"@types/semver": "^7.7.1",
|
|
77
|
-
"@vitest/coverage-istanbul": "^4.1.
|
|
79
|
+
"@vitest/coverage-istanbul": "^4.1.8",
|
|
78
80
|
"babel-plugin-react-compiler": "^1.0.0",
|
|
79
81
|
"eslint": "^10.2.1",
|
|
80
82
|
"jsdom": "^29.1.1",
|
|
83
|
+
"magic-string": "^0.30.21",
|
|
81
84
|
"publint": "^0.3.21",
|
|
82
85
|
"sanity": "^5.30.0",
|
|
86
|
+
"styled-components": "^6.4.0",
|
|
83
87
|
"typescript": "^5.9.3",
|
|
84
|
-
"vitest": "^4.1.
|
|
88
|
+
"vitest": "^4.1.8",
|
|
85
89
|
"@repo/package.config": "0.0.1",
|
|
86
90
|
"@repo/tsconfig": "3.70.0",
|
|
87
|
-
"@sanity/cli-test": "0.
|
|
91
|
+
"@sanity/cli-test": "1.0.0",
|
|
88
92
|
"@sanity/eslint-config-cli": "^1.1.1"
|
|
89
93
|
},
|
|
90
94
|
"peerDependencies": {
|