vinext 0.0.39 → 0.0.40
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/build/standalone.js +7 -0
- package/dist/build/standalone.js.map +1 -1
- package/dist/entries/app-rsc-entry.d.ts +2 -1
- package/dist/entries/app-rsc-entry.js +131 -245
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/index.d.ts +32 -1
- package/dist/index.js +80 -6
- package/dist/index.js.map +1 -1
- package/dist/plugins/server-externals-manifest.d.ts +11 -1
- package/dist/plugins/server-externals-manifest.js +10 -3
- package/dist/plugins/server-externals-manifest.js.map +1 -1
- package/dist/routing/app-router.d.ts +10 -2
- package/dist/routing/app-router.js +37 -22
- package/dist/routing/app-router.js.map +1 -1
- package/dist/server/app-page-response.d.ts +12 -1
- package/dist/server/app-page-response.js +26 -7
- package/dist/server/app-page-response.js.map +1 -1
- package/dist/server/app-page-route-wiring.d.ts +79 -0
- package/dist/server/app-page-route-wiring.js +165 -0
- package/dist/server/app-page-route-wiring.js.map +1 -0
- package/dist/server/app-page-stream.js +3 -0
- package/dist/server/app-page-stream.js.map +1 -1
- package/dist/server/app-route-handler-response.js +4 -1
- package/dist/server/app-route-handler-response.js.map +1 -1
- package/dist/server/app-router-entry.d.ts +6 -1
- package/dist/server/app-router-entry.js +9 -2
- package/dist/server/app-router-entry.js.map +1 -1
- package/dist/server/prod-server.d.ts +1 -1
- package/dist/server/prod-server.js +37 -11
- package/dist/server/prod-server.js.map +1 -1
- package/dist/server/worker-utils.d.ts +4 -1
- package/dist/server/worker-utils.js +31 -1
- package/dist/server/worker-utils.js.map +1 -1
- package/dist/shims/error-boundary.d.ts +13 -4
- package/dist/shims/error-boundary.js +23 -3
- package/dist/shims/error-boundary.js.map +1 -1
- package/dist/shims/head.js.map +1 -1
- package/dist/shims/navigation.d.ts +16 -1
- package/dist/shims/navigation.js +18 -3
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/router.js +127 -38
- package/dist/shims/router.js.map +1 -1
- package/dist/shims/script.js.map +1 -1
- package/dist/shims/server.d.ts +17 -4
- package/dist/shims/server.js +91 -73
- package/dist/shims/server.js.map +1 -1
- package/dist/shims/slot.d.ts +28 -0
- package/dist/shims/slot.js +49 -0
- package/dist/shims/slot.js.map +1 -0
- package/package.json +1 -2
package/dist/build/standalone.js
CHANGED
|
@@ -41,6 +41,13 @@ function resolvePackageJsonPath(packageName, resolver) {
|
|
|
41
41
|
try {
|
|
42
42
|
return resolver.resolve(`${packageName}/package.json`);
|
|
43
43
|
} catch {
|
|
44
|
+
const lookupPaths = resolver.resolve.paths(packageName) ?? [];
|
|
45
|
+
for (const lookupPath of lookupPaths) {
|
|
46
|
+
const candidate = path.join(lookupPath, packageName, "package.json");
|
|
47
|
+
if (fs.existsSync(candidate)) {
|
|
48
|
+
if (readPackageJson(candidate).name === packageName) return candidate;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
44
51
|
try {
|
|
45
52
|
const entryPath = resolver.resolve(packageName);
|
|
46
53
|
let dir = path.dirname(entryPath);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"standalone.js","names":[],"sources":["../../src/build/standalone.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { createRequire } from \"node:module\";\nimport { resolveVinextPackageRoot } from \"../utils/vinext-root.js\";\n\ntype PackageJson = {\n name?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n optionalDependencies?: Record<string, string>;\n};\n\nexport type StandaloneBuildOptions = {\n root: string;\n outDir: string;\n /**\n * Test hook: override vinext package root used for embedding runtime files.\n */\n vinextPackageRoot?: string;\n};\n\nexport type StandaloneBuildResult = {\n standaloneDir: string;\n copiedPackages: string[];\n};\n\ntype QueueEntry = {\n packageName: string;\n resolver: NodeRequire;\n optional: boolean;\n};\n\nfunction readPackageJson(packageJsonPath: string): PackageJson {\n return JSON.parse(fs.readFileSync(packageJsonPath, \"utf-8\")) as PackageJson;\n}\n\n/** Returns both `dependencies` and `optionalDependencies` keys — the full set of potential runtime deps. */\nfunction runtimeDeps(pkg: PackageJson): string[] {\n return Object.keys({\n ...pkg.dependencies,\n ...pkg.optionalDependencies,\n });\n}\n\n/**\n * Read the externals manifest written by the `vinext:server-externals-manifest`\n * Vite plugin during the production build.\n *\n * The manifest (`dist/server/vinext-externals.json`) contains the exact set of\n * npm packages that the bundler left external in the SSR/RSC output — i.e.\n * packages that the server bundle actually imports at runtime. Using this\n * instead of scanning emitted files with regexes or seeding from\n * `package.json#dependencies` avoids both false negatives (missed imports) and\n * false positives (client-only deps that are never loaded server-side).\n *\n * Falls back to an empty array if the manifest does not exist (e.g. when\n * running against a build that predates this feature).\n */\nfunction readServerExternalsManifest(serverDir: string): string[] {\n const manifestPath = path.join(serverDir, \"vinext-externals.json\");\n if (!fs.existsSync(manifestPath)) {\n return [];\n }\n try {\n return JSON.parse(fs.readFileSync(manifestPath, \"utf-8\")) as string[];\n } catch (err) {\n console.warn(\n `[vinext] Warning: failed to parse ${manifestPath}, proceeding without externals manifest: ${String(err)}`,\n );\n return [];\n }\n}\n\nfunction resolvePackageJsonPath(packageName: string, resolver: NodeRequire): string | null {\n try {\n return resolver.resolve(`${packageName}/package.json`);\n } catch {\n // Some packages do not export ./package.json via exports map.\n // Fallback: resolve package entry and walk up to the nearest matching package.json.\n try {\n const entryPath = resolver.resolve(packageName);\n let dir = path.dirname(entryPath);\n while (dir !== path.dirname(dir)) {\n const candidate = path.join(dir, \"package.json\");\n if (fs.existsSync(candidate)) {\n const pkg = readPackageJson(candidate);\n if (pkg.name === packageName) {\n return candidate;\n }\n }\n dir = path.dirname(dir);\n }\n } catch {\n // fallthrough to null\n }\n return null;\n }\n}\n\nfunction copyPackageAndRuntimeDeps(\n root: string,\n targetNodeModulesDir: string,\n initialPackages: string[],\n alreadyCopied?: Set<string>,\n): string[] {\n // Returns the full set of package names in `copied` after the BFS completes —\n // including any entries that were already in `alreadyCopied` before this call.\n // Callers that need to track incremental additions should diff against their\n // own snapshot, or use the shared `alreadyCopied` set directly.\n const rootResolver = createRequire(path.join(root, \"package.json\"));\n const rootPkg = readPackageJson(path.join(root, \"package.json\"));\n const rootOptional = new Set(Object.keys(rootPkg.optionalDependencies ?? {}));\n const copied = alreadyCopied ?? new Set<string>();\n const queue: QueueEntry[] = initialPackages.map((packageName) => ({\n packageName,\n resolver: rootResolver,\n optional: rootOptional.has(packageName),\n }));\n\n while (queue.length > 0) {\n const entry = queue.shift();\n if (!entry) continue;\n if (copied.has(entry.packageName)) continue;\n\n const packageJsonPath = resolvePackageJsonPath(entry.packageName, entry.resolver);\n if (!packageJsonPath) {\n if (entry.optional) {\n continue;\n }\n throw new Error(\n `Failed to resolve required runtime dependency \"${entry.packageName}\" for standalone output`,\n );\n }\n\n const packageRoot = path.dirname(packageJsonPath);\n const packageTarget = path.join(targetNodeModulesDir, entry.packageName);\n fs.mkdirSync(path.dirname(packageTarget), { recursive: true });\n fs.cpSync(packageRoot, packageTarget, {\n recursive: true,\n dereference: true,\n // Skip any nested node_modules/ inside the package — the BFS walk\n // resolves deps at their correct hoisted location, so nested copies\n // would be stale duplicates. Use path segment splitting so that a\n // directory merely containing \"node_modules\" as a substring (e.g.\n // \"not_node_modules_v2\") is not accidentally filtered out.\n filter: (src) => {\n const rel = path.relative(packageRoot, src);\n return !rel.split(path.sep).includes(\"node_modules\");\n },\n });\n\n copied.add(entry.packageName);\n\n const packageResolver = createRequire(packageJsonPath);\n const pkg = readPackageJson(packageJsonPath);\n const optionalDeps = new Set(Object.keys(pkg.optionalDependencies ?? {}));\n for (const depName of runtimeDeps(pkg)) {\n if (!copied.has(depName)) {\n queue.push({\n packageName: depName,\n resolver: packageResolver,\n optional: optionalDeps.has(depName),\n });\n }\n }\n }\n\n return [...copied];\n}\n\nfunction writeStandaloneServerEntry(filePath: string): void {\n // Uses import.meta.dirname (Node >= 21.2, vinext requires >= 22) so the\n // entry point is pure ESM — no need for CJS require() or __dirname.\n //\n // The static import of \"vinext/server/prod-server\" is intentional: that\n // subpath is a documented export in vinext's package.json exports map and\n // is always present in the standalone node_modules/vinext/dist tree\n // (emitStandaloneOutput copies vinext's dist/ directory in full). A static\n // import gives a clearer ERR_MODULE_NOT_FOUND at startup rather than a\n // runtime error deep inside the server if the import were deferred.\n const content = `#!/usr/bin/env node\nimport { join } from \"node:path\";\nimport { startProdServer } from \"vinext/server/prod-server\";\n\nconst port = Number.parseInt(process.env.PORT ?? \"3000\", 10);\nconst host = process.env.HOST ?? \"0.0.0.0\";\n\nstartProdServer({\n port,\n host,\n outDir: join(import.meta.dirname, \"dist\"),\n}).catch((error) => {\n console.error(\"[vinext] Failed to start standalone server\");\n console.error(error);\n process.exit(1);\n});\n`;\n fs.writeFileSync(filePath, content, \"utf-8\");\n fs.chmodSync(filePath, 0o755);\n}\n\nfunction writeStandalonePackageJson(filePath: string): void {\n fs.writeFileSync(\n filePath,\n JSON.stringify(\n {\n private: true,\n type: \"module\",\n },\n null,\n 2,\n ) + \"\\n\",\n \"utf-8\",\n );\n}\n\n/**\n * Emit standalone production output for self-hosted deployments.\n *\n * Creates:\n * - <outDir>/standalone/server.js\n * - <outDir>/standalone/dist/{client,server}\n * - <outDir>/standalone/node_modules (runtime deps only)\n *\n * The set of packages copied into node_modules/ is determined by\n * `dist/server/vinext-externals.json`, which is written by the\n * `vinext:server-externals-manifest` Vite plugin during the production build.\n * It contains exactly the packages the server bundle imports at runtime\n * (i.e. those left external by the bundler), so no client-only deps are\n * included.\n */\nexport function emitStandaloneOutput(options: StandaloneBuildOptions): StandaloneBuildResult {\n const root = path.resolve(options.root);\n const outDir = path.resolve(options.outDir);\n const clientDir = path.join(outDir, \"client\");\n const serverDir = path.join(outDir, \"server\");\n\n if (!fs.existsSync(clientDir) || !fs.existsSync(serverDir)) {\n throw new Error(`No build output found in ${outDir}. Run vinext build first.`);\n }\n\n const standaloneDir = path.join(outDir, \"standalone\");\n const standaloneDistDir = path.join(standaloneDir, \"dist\");\n const standaloneNodeModulesDir = path.join(standaloneDir, \"node_modules\");\n\n fs.rmSync(standaloneDir, { recursive: true, force: true });\n fs.mkdirSync(standaloneDistDir, { recursive: true });\n\n fs.cpSync(clientDir, path.join(standaloneDistDir, \"client\"), {\n recursive: true,\n dereference: true,\n // Build output shouldn't contain node_modules, but filter defensively for\n // consistency with the other cpSync calls in this function.\n filter: (src) => !path.relative(clientDir, src).split(path.sep).includes(\"node_modules\"),\n });\n fs.cpSync(serverDir, path.join(standaloneDistDir, \"server\"), {\n recursive: true,\n dereference: true,\n filter: (src) => !path.relative(serverDir, src).split(path.sep).includes(\"node_modules\"),\n });\n\n const publicDir = path.join(root, \"public\");\n if (fs.existsSync(publicDir)) {\n fs.cpSync(publicDir, path.join(standaloneDir, \"public\"), {\n recursive: true,\n dereference: true,\n // Defensive: public/ containing node_modules is extremely unlikely but\n // filter for consistency with the other cpSync calls in this function.\n filter: (src) => !path.relative(publicDir, src).split(path.sep).includes(\"node_modules\"),\n });\n }\n\n fs.mkdirSync(standaloneNodeModulesDir, { recursive: true });\n\n // Seed from the manifest written by vinext:server-externals-manifest during\n // the production build. This is the authoritative list of packages the server\n // bundle actually imports at runtime — determined by the bundler's own graph,\n // not regex scanning or package.json#dependencies.\n //\n // The manifest is always written to dist/server/vinext-externals.json regardless\n // of whether the build is App Router (rsc + ssr sub-dirs) or Pages Router (ssr\n // only). The plugin walks up from options.dir to find the \"server\" ancestor, so\n // both dist/server (Pages Router) and dist/server/ssr (App Router SSR) resolve\n // to the same dist/server output path.\n const initialPackages = readServerExternalsManifest(serverDir).filter(\n (name) => name !== \"vinext\",\n );\n const copiedSet = new Set<string>();\n copyPackageAndRuntimeDeps(root, standaloneNodeModulesDir, initialPackages, copiedSet);\n\n // Always embed the exact vinext runtime that produced this build.\n const vinextPackageRoot = resolveVinextPackageRoot(options.vinextPackageRoot);\n const vinextDistDir = path.join(vinextPackageRoot, \"dist\");\n if (!fs.existsSync(vinextDistDir)) {\n throw new Error(`vinext runtime dist/ not found at ${vinextPackageRoot}`);\n }\n const vinextTargetDir = path.join(standaloneNodeModulesDir, \"vinext\");\n fs.mkdirSync(vinextTargetDir, { recursive: true });\n fs.copyFileSync(\n path.join(vinextPackageRoot, \"package.json\"),\n path.join(vinextTargetDir, \"package.json\"),\n );\n fs.cpSync(vinextDistDir, path.join(vinextTargetDir, \"dist\"), {\n recursive: true,\n dereference: true,\n // Defensive: skip any node_modules/ that may exist inside vinext's dist/.\n filter: (src) => {\n const rel = path.relative(vinextDistDir, src);\n return !rel.split(path.sep).includes(\"node_modules\");\n },\n });\n copiedSet.add(\"vinext\");\n\n // Copy vinext's own runtime dependencies. The prod-server imports packages\n // like `rsc-html-stream` at runtime; they must be present in standalone\n // node_modules/ even if the user's app doesn't depend on them directly.\n // We resolve them from vinext's package root so nested requires work correctly.\n const vinextPkg = readPackageJson(path.join(vinextPackageRoot, \"package.json\"));\n const vinextRuntimeDeps = runtimeDeps(vinextPkg).filter((name) => !copiedSet.has(name));\n copyPackageAndRuntimeDeps(\n vinextPackageRoot,\n standaloneNodeModulesDir,\n vinextRuntimeDeps,\n copiedSet,\n );\n\n writeStandaloneServerEntry(path.join(standaloneDir, \"server.js\"));\n writeStandalonePackageJson(path.join(standaloneDir, \"package.json\"));\n\n return {\n standaloneDir,\n copiedPackages: [...copiedSet],\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"standalone.js","names":[],"sources":["../../src/build/standalone.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { createRequire } from \"node:module\";\nimport { resolveVinextPackageRoot } from \"../utils/vinext-root.js\";\n\ntype PackageJson = {\n name?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n optionalDependencies?: Record<string, string>;\n};\n\nexport type StandaloneBuildOptions = {\n root: string;\n outDir: string;\n /**\n * Test hook: override vinext package root used for embedding runtime files.\n */\n vinextPackageRoot?: string;\n};\n\nexport type StandaloneBuildResult = {\n standaloneDir: string;\n copiedPackages: string[];\n};\n\ntype QueueEntry = {\n packageName: string;\n resolver: NodeRequire;\n optional: boolean;\n};\n\nfunction readPackageJson(packageJsonPath: string): PackageJson {\n return JSON.parse(fs.readFileSync(packageJsonPath, \"utf-8\")) as PackageJson;\n}\n\n/** Returns both `dependencies` and `optionalDependencies` keys — the full set of potential runtime deps. */\nfunction runtimeDeps(pkg: PackageJson): string[] {\n return Object.keys({\n ...pkg.dependencies,\n ...pkg.optionalDependencies,\n });\n}\n\n/**\n * Read the externals manifest written by the `vinext:server-externals-manifest`\n * Vite plugin during the production build.\n *\n * The manifest (`dist/server/vinext-externals.json`) contains the exact set of\n * npm packages that the bundler left external in the SSR/RSC output — i.e.\n * packages that the server bundle actually imports at runtime. Using this\n * instead of scanning emitted files with regexes or seeding from\n * `package.json#dependencies` avoids both false negatives (missed imports) and\n * false positives (client-only deps that are never loaded server-side).\n *\n * Falls back to an empty array if the manifest does not exist (e.g. when\n * running against a build that predates this feature).\n */\nfunction readServerExternalsManifest(serverDir: string): string[] {\n const manifestPath = path.join(serverDir, \"vinext-externals.json\");\n if (!fs.existsSync(manifestPath)) {\n return [];\n }\n try {\n return JSON.parse(fs.readFileSync(manifestPath, \"utf-8\")) as string[];\n } catch (err) {\n console.warn(\n `[vinext] Warning: failed to parse ${manifestPath}, proceeding without externals manifest: ${String(err)}`,\n );\n return [];\n }\n}\n\nfunction resolvePackageJsonPath(packageName: string, resolver: NodeRequire): string | null {\n try {\n return resolver.resolve(`${packageName}/package.json`);\n } catch {\n // Some packages only expose subpath exports (for example `rsc-html-stream`,\n // which exports `./server` but not `.` or `./package.json`). resolver.resolve()\n // cannot access those hidden paths, but Node still exposes the installed\n // node_modules lookup locations via resolve.paths().\n const lookupPaths = resolver.resolve.paths(packageName) ?? [];\n for (const lookupPath of lookupPaths) {\n const candidate = path.join(lookupPath, packageName, \"package.json\");\n if (fs.existsSync(candidate)) {\n const pkg = readPackageJson(candidate);\n if (pkg.name === packageName) {\n return candidate;\n }\n }\n }\n\n // Some packages do not export ./package.json via exports map.\n // Fallback: resolve package entry and walk up to the nearest matching package.json.\n try {\n const entryPath = resolver.resolve(packageName);\n let dir = path.dirname(entryPath);\n while (dir !== path.dirname(dir)) {\n const candidate = path.join(dir, \"package.json\");\n if (fs.existsSync(candidate)) {\n const pkg = readPackageJson(candidate);\n if (pkg.name === packageName) {\n return candidate;\n }\n }\n dir = path.dirname(dir);\n }\n } catch {\n // fallthrough to null\n }\n return null;\n }\n}\n\nfunction copyPackageAndRuntimeDeps(\n root: string,\n targetNodeModulesDir: string,\n initialPackages: string[],\n alreadyCopied?: Set<string>,\n): string[] {\n // Returns the full set of package names in `copied` after the BFS completes —\n // including any entries that were already in `alreadyCopied` before this call.\n // Callers that need to track incremental additions should diff against their\n // own snapshot, or use the shared `alreadyCopied` set directly.\n const rootResolver = createRequire(path.join(root, \"package.json\"));\n const rootPkg = readPackageJson(path.join(root, \"package.json\"));\n const rootOptional = new Set(Object.keys(rootPkg.optionalDependencies ?? {}));\n const copied = alreadyCopied ?? new Set<string>();\n const queue: QueueEntry[] = initialPackages.map((packageName) => ({\n packageName,\n resolver: rootResolver,\n optional: rootOptional.has(packageName),\n }));\n\n while (queue.length > 0) {\n const entry = queue.shift();\n if (!entry) continue;\n if (copied.has(entry.packageName)) continue;\n\n const packageJsonPath = resolvePackageJsonPath(entry.packageName, entry.resolver);\n if (!packageJsonPath) {\n if (entry.optional) {\n continue;\n }\n throw new Error(\n `Failed to resolve required runtime dependency \"${entry.packageName}\" for standalone output`,\n );\n }\n\n const packageRoot = path.dirname(packageJsonPath);\n const packageTarget = path.join(targetNodeModulesDir, entry.packageName);\n fs.mkdirSync(path.dirname(packageTarget), { recursive: true });\n fs.cpSync(packageRoot, packageTarget, {\n recursive: true,\n dereference: true,\n // Skip any nested node_modules/ inside the package — the BFS walk\n // resolves deps at their correct hoisted location, so nested copies\n // would be stale duplicates. Use path segment splitting so that a\n // directory merely containing \"node_modules\" as a substring (e.g.\n // \"not_node_modules_v2\") is not accidentally filtered out.\n filter: (src) => {\n const rel = path.relative(packageRoot, src);\n return !rel.split(path.sep).includes(\"node_modules\");\n },\n });\n\n copied.add(entry.packageName);\n\n const packageResolver = createRequire(packageJsonPath);\n const pkg = readPackageJson(packageJsonPath);\n const optionalDeps = new Set(Object.keys(pkg.optionalDependencies ?? {}));\n for (const depName of runtimeDeps(pkg)) {\n if (!copied.has(depName)) {\n queue.push({\n packageName: depName,\n resolver: packageResolver,\n optional: optionalDeps.has(depName),\n });\n }\n }\n }\n\n return [...copied];\n}\n\nfunction writeStandaloneServerEntry(filePath: string): void {\n // Uses import.meta.dirname (Node >= 21.2, vinext requires >= 22) so the\n // entry point is pure ESM — no need for CJS require() or __dirname.\n //\n // The static import of \"vinext/server/prod-server\" is intentional: that\n // subpath is a documented export in vinext's package.json exports map and\n // is always present in the standalone node_modules/vinext/dist tree\n // (emitStandaloneOutput copies vinext's dist/ directory in full). A static\n // import gives a clearer ERR_MODULE_NOT_FOUND at startup rather than a\n // runtime error deep inside the server if the import were deferred.\n const content = `#!/usr/bin/env node\nimport { join } from \"node:path\";\nimport { startProdServer } from \"vinext/server/prod-server\";\n\nconst port = Number.parseInt(process.env.PORT ?? \"3000\", 10);\nconst host = process.env.HOST ?? \"0.0.0.0\";\n\nstartProdServer({\n port,\n host,\n outDir: join(import.meta.dirname, \"dist\"),\n}).catch((error) => {\n console.error(\"[vinext] Failed to start standalone server\");\n console.error(error);\n process.exit(1);\n});\n`;\n fs.writeFileSync(filePath, content, \"utf-8\");\n fs.chmodSync(filePath, 0o755);\n}\n\nfunction writeStandalonePackageJson(filePath: string): void {\n fs.writeFileSync(\n filePath,\n JSON.stringify(\n {\n private: true,\n type: \"module\",\n },\n null,\n 2,\n ) + \"\\n\",\n \"utf-8\",\n );\n}\n\n/**\n * Emit standalone production output for self-hosted deployments.\n *\n * Creates:\n * - <outDir>/standalone/server.js\n * - <outDir>/standalone/dist/{client,server}\n * - <outDir>/standalone/node_modules (runtime deps only)\n *\n * The set of packages copied into node_modules/ is determined by\n * `dist/server/vinext-externals.json`, which is written by the\n * `vinext:server-externals-manifest` Vite plugin during the production build.\n * It contains exactly the packages the server bundle imports at runtime\n * (i.e. those left external by the bundler), so no client-only deps are\n * included.\n */\nexport function emitStandaloneOutput(options: StandaloneBuildOptions): StandaloneBuildResult {\n const root = path.resolve(options.root);\n const outDir = path.resolve(options.outDir);\n const clientDir = path.join(outDir, \"client\");\n const serverDir = path.join(outDir, \"server\");\n\n if (!fs.existsSync(clientDir) || !fs.existsSync(serverDir)) {\n throw new Error(`No build output found in ${outDir}. Run vinext build first.`);\n }\n\n const standaloneDir = path.join(outDir, \"standalone\");\n const standaloneDistDir = path.join(standaloneDir, \"dist\");\n const standaloneNodeModulesDir = path.join(standaloneDir, \"node_modules\");\n\n fs.rmSync(standaloneDir, { recursive: true, force: true });\n fs.mkdirSync(standaloneDistDir, { recursive: true });\n\n fs.cpSync(clientDir, path.join(standaloneDistDir, \"client\"), {\n recursive: true,\n dereference: true,\n // Build output shouldn't contain node_modules, but filter defensively for\n // consistency with the other cpSync calls in this function.\n filter: (src) => !path.relative(clientDir, src).split(path.sep).includes(\"node_modules\"),\n });\n fs.cpSync(serverDir, path.join(standaloneDistDir, \"server\"), {\n recursive: true,\n dereference: true,\n filter: (src) => !path.relative(serverDir, src).split(path.sep).includes(\"node_modules\"),\n });\n\n const publicDir = path.join(root, \"public\");\n if (fs.existsSync(publicDir)) {\n fs.cpSync(publicDir, path.join(standaloneDir, \"public\"), {\n recursive: true,\n dereference: true,\n // Defensive: public/ containing node_modules is extremely unlikely but\n // filter for consistency with the other cpSync calls in this function.\n filter: (src) => !path.relative(publicDir, src).split(path.sep).includes(\"node_modules\"),\n });\n }\n\n fs.mkdirSync(standaloneNodeModulesDir, { recursive: true });\n\n // Seed from the manifest written by vinext:server-externals-manifest during\n // the production build. This is the authoritative list of packages the server\n // bundle actually imports at runtime — determined by the bundler's own graph,\n // not regex scanning or package.json#dependencies.\n //\n // The manifest is always written to dist/server/vinext-externals.json regardless\n // of whether the build is App Router (rsc + ssr sub-dirs) or Pages Router (ssr\n // only). The plugin walks up from options.dir to find the \"server\" ancestor, so\n // both dist/server (Pages Router) and dist/server/ssr (App Router SSR) resolve\n // to the same dist/server output path.\n const initialPackages = readServerExternalsManifest(serverDir).filter(\n (name) => name !== \"vinext\",\n );\n const copiedSet = new Set<string>();\n copyPackageAndRuntimeDeps(root, standaloneNodeModulesDir, initialPackages, copiedSet);\n\n // Always embed the exact vinext runtime that produced this build.\n const vinextPackageRoot = resolveVinextPackageRoot(options.vinextPackageRoot);\n const vinextDistDir = path.join(vinextPackageRoot, \"dist\");\n if (!fs.existsSync(vinextDistDir)) {\n throw new Error(`vinext runtime dist/ not found at ${vinextPackageRoot}`);\n }\n const vinextTargetDir = path.join(standaloneNodeModulesDir, \"vinext\");\n fs.mkdirSync(vinextTargetDir, { recursive: true });\n fs.copyFileSync(\n path.join(vinextPackageRoot, \"package.json\"),\n path.join(vinextTargetDir, \"package.json\"),\n );\n fs.cpSync(vinextDistDir, path.join(vinextTargetDir, \"dist\"), {\n recursive: true,\n dereference: true,\n // Defensive: skip any node_modules/ that may exist inside vinext's dist/.\n filter: (src) => {\n const rel = path.relative(vinextDistDir, src);\n return !rel.split(path.sep).includes(\"node_modules\");\n },\n });\n copiedSet.add(\"vinext\");\n\n // Copy vinext's own runtime dependencies. The prod-server imports packages\n // like `rsc-html-stream` at runtime; they must be present in standalone\n // node_modules/ even if the user's app doesn't depend on them directly.\n // We resolve them from vinext's package root so nested requires work correctly.\n const vinextPkg = readPackageJson(path.join(vinextPackageRoot, \"package.json\"));\n const vinextRuntimeDeps = runtimeDeps(vinextPkg).filter((name) => !copiedSet.has(name));\n copyPackageAndRuntimeDeps(\n vinextPackageRoot,\n standaloneNodeModulesDir,\n vinextRuntimeDeps,\n copiedSet,\n );\n\n writeStandaloneServerEntry(path.join(standaloneDir, \"server.js\"));\n writeStandalonePackageJson(path.join(standaloneDir, \"package.json\"));\n\n return {\n standaloneDir,\n copiedPackages: [...copiedSet],\n };\n}\n"],"mappings":"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"}
|
|
@@ -27,7 +27,8 @@ type AppRouterConfig = {
|
|
|
27
27
|
* `import("./ssr/index.js")`, which re-exports it from
|
|
28
28
|
* `virtual:vinext-server-entry` when this flag is set.
|
|
29
29
|
*/
|
|
30
|
-
hasPagesDir?: boolean;
|
|
30
|
+
hasPagesDir?: boolean; /** Exact public/ file routes, using normalized leading-slash pathnames. */
|
|
31
|
+
publicFiles?: string[];
|
|
31
32
|
};
|
|
32
33
|
/**
|
|
33
34
|
* Generate the virtual RSC entry module.
|