@vistagenic/vista 0.2.10 → 0.2.13

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.
Files changed (77) hide show
  1. package/bin/vista.js +183 -36
  2. package/dist/bin/build-rsc-flashpack.d.ts +4 -0
  3. package/dist/bin/build-rsc-flashpack.js +29 -0
  4. package/dist/bin/build-rsc.js +61 -16
  5. package/dist/bin/build.js +36 -13
  6. package/dist/bin/devtools-indicator-snippet.js +30 -0
  7. package/dist/bin/file-scanner.d.ts +1 -1
  8. package/dist/bin/file-scanner.js +8 -0
  9. package/dist/bin/flashpack-runner.d.ts +1 -0
  10. package/dist/bin/flashpack-runner.js +61 -0
  11. package/dist/bin/server-component-plugin.d.ts +6 -4
  12. package/dist/bin/server-component-plugin.js +22 -69
  13. package/dist/bin/webpack.config.d.ts +3 -0
  14. package/dist/bin/webpack.config.js +12 -3
  15. package/dist/build/manifest.d.ts +17 -3
  16. package/dist/build/manifest.js +99 -23
  17. package/dist/build/rsc/compiler.d.ts +2 -0
  18. package/dist/build/rsc/compiler.js +25 -5
  19. package/dist/build/rsc/react-client-reference-manifest.d.ts +22 -0
  20. package/dist/build/rsc/react-client-reference-manifest.js +219 -0
  21. package/dist/build/rsc/server-manifest.d.ts +23 -2
  22. package/dist/build/rsc/server-manifest.js +162 -24
  23. package/dist/build/standalone.d.ts +31 -0
  24. package/dist/build/standalone.js +334 -0
  25. package/dist/client/rsc-router.d.ts +31 -0
  26. package/dist/client/rsc-router.js +89 -0
  27. package/dist/config.d.ts +23 -0
  28. package/dist/config.js +106 -5
  29. package/dist/constants.d.ts +2 -0
  30. package/dist/constants.js +3 -1
  31. package/dist/flashpack/command.d.ts +8 -0
  32. package/dist/flashpack/command.js +134 -0
  33. package/dist/flashpack/runtime.d.ts +39 -0
  34. package/dist/flashpack/runtime.js +249 -0
  35. package/dist/server/app-router-runtime.d.ts +26 -0
  36. package/dist/server/app-router-runtime.js +321 -0
  37. package/dist/server/artifact-validator.js +21 -1
  38. package/dist/server/cache.d.ts +10 -0
  39. package/dist/server/cache.js +270 -0
  40. package/dist/server/client-boundary.js +20 -2
  41. package/dist/server/engine.js +236 -159
  42. package/dist/server/fetch-policy.d.ts +2 -0
  43. package/dist/server/fetch-policy.js +123 -0
  44. package/dist/server/index.d.ts +7 -0
  45. package/dist/server/index.js +131 -22
  46. package/dist/server/module-boundary-validator.d.ts +15 -0
  47. package/dist/server/module-boundary-validator.js +262 -0
  48. package/dist/server/module-compile-hook.d.ts +7 -0
  49. package/dist/server/module-compile-hook.js +662 -0
  50. package/dist/server/ppr.d.ts +18 -0
  51. package/dist/server/ppr.js +59 -0
  52. package/dist/server/request-context.d.ts +31 -0
  53. package/dist/server/request-context.js +95 -0
  54. package/dist/server/rsc-engine-flashpack.d.ts +4 -0
  55. package/dist/server/rsc-engine-flashpack.js +27 -0
  56. package/dist/server/rsc-engine.d.ts +2 -0
  57. package/dist/server/rsc-engine.js +589 -317
  58. package/dist/server/rsc-upstream.js +539 -233
  59. package/dist/server/runtime-actions.d.ts +5 -0
  60. package/dist/server/runtime-actions.js +80 -0
  61. package/dist/server/runtime-artifacts.d.ts +11 -0
  62. package/dist/server/runtime-artifacts.js +35 -0
  63. package/dist/server/segment-config.d.ts +37 -0
  64. package/dist/server/segment-config.js +205 -0
  65. package/dist/server/spawn-permissions.d.ts +2 -0
  66. package/dist/server/spawn-permissions.js +21 -0
  67. package/dist/server/static-cache.d.ts +15 -1
  68. package/dist/server/static-cache.js +83 -3
  69. package/dist/server/static-generator.js +254 -100
  70. package/dist/server/structure-validator.d.ts +1 -1
  71. package/dist/server/structure-validator.js +26 -5
  72. package/dist/server/structure-watch.js +1 -1
  73. package/dist/server/typed-api-runtime.d.ts +1 -0
  74. package/dist/server/typed-api-runtime.js +145 -25
  75. package/dist/server/vista-import-map.d.ts +1 -0
  76. package/dist/server/vista-import-map.js +123 -0
  77. package/package.json +13 -1
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const fs_1 = __importDefault(require("fs"));
7
+ const path_1 = __importDefault(require("path"));
8
+ const build_rsc_1 = require("./build-rsc");
9
+ const rsc_engine_1 = require("../server/rsc-engine");
10
+ function parseCliArg(flag) {
11
+ const index = process.argv.indexOf(flag);
12
+ if (index === -1)
13
+ return undefined;
14
+ return process.argv[index + 1];
15
+ }
16
+ function normalizePhase(raw) {
17
+ const value = String(raw || '')
18
+ .trim()
19
+ .toLowerCase();
20
+ if (value === 'dev' || value === 'development')
21
+ return 'dev';
22
+ if (value === 'start')
23
+ return 'start';
24
+ return 'build';
25
+ }
26
+ async function main() {
27
+ const phase = normalizePhase(parseCliArg('--phase'));
28
+ const rawPort = parseCliArg('--port') || process.env.PORT || '3003';
29
+ const port = Number(rawPort) || 3003;
30
+ process.env.VISTA_ENGINE = 'flashpack';
31
+ process.env.VISTA_ENGINE_VARIANT = 'flashpack';
32
+ process.env.VISTA_FLASHPACK = 'true';
33
+ process.env.VISTA_FLASHPACK_PIPELINE = process.env.VISTA_FLASHPACK_PIPELINE || 'rust-cli';
34
+ if (phase === 'build') {
35
+ await (0, build_rsc_1.buildRSC)(false);
36
+ return;
37
+ }
38
+ if (phase === 'dev') {
39
+ const buildResult = await (0, build_rsc_1.buildRSC)(true);
40
+ (0, rsc_engine_1.startRSCServer)({
41
+ port,
42
+ compiler: buildResult.clientCompiler,
43
+ });
44
+ return;
45
+ }
46
+ const standaloneServerPath = path_1.default.join(process.cwd(), '.vista', 'standalone', 'server.js');
47
+ if (fs_1.default.existsSync(standaloneServerPath)) {
48
+ const standalone = require(standaloneServerPath);
49
+ const startStandaloneServer = standalone.startStandaloneServer || standalone.default || standalone;
50
+ startStandaloneServer({
51
+ port,
52
+ engine: 'flashpack',
53
+ });
54
+ return;
55
+ }
56
+ (0, rsc_engine_1.startRSCServer)({ port });
57
+ }
58
+ main().catch((error) => {
59
+ console.error(error && error.stack ? error.stack : error);
60
+ process.exit(1);
61
+ });
@@ -1,17 +1,19 @@
1
1
  /**
2
2
  * Vista Server Component Webpack Plugin
3
3
  *
4
- * Checks for server component violations on every webpack compilation.
5
- * Fails the build if client hooks are used without 'use client' directive.
4
+ * Checks for server/client boundary violations and invalid route segment
5
+ * config on every webpack compilation.
6
6
  */
7
7
  import type { Compiler } from 'webpack';
8
8
  export declare class VistaServerComponentPlugin {
9
9
  private appDir;
10
+ private componentsDir?;
11
+ private cacheComponentsEnabled;
10
12
  constructor(options: {
11
13
  appDir: string;
14
+ componentsDir?: string;
15
+ cacheComponentsEnabled?: boolean;
12
16
  });
13
17
  apply(compiler: Compiler): void;
14
- private checkServerComponents;
15
- private scanDirectory;
16
18
  }
17
19
  export default VistaServerComponentPlugin;
@@ -2,8 +2,8 @@
2
2
  /**
3
3
  * Vista Server Component Webpack Plugin
4
4
  *
5
- * Checks for server component violations on every webpack compilation.
6
- * Fails the build if client hooks are used without 'use client' directive.
5
+ * Checks for server/client boundary violations and invalid route segment
6
+ * config on every webpack compilation.
7
7
  */
8
8
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
9
  if (k2 === undefined) k2 = k;
@@ -40,94 +40,47 @@ var __importStar = (this && this.__importStar) || (function () {
40
40
  })();
41
41
  Object.defineProperty(exports, "__esModule", { value: true });
42
42
  exports.VistaServerComponentPlugin = void 0;
43
- const fs = __importStar(require("fs"));
44
43
  const path = __importStar(require("path"));
45
- // Client-only hooks and APIs that require 'use client' directive
46
- const CLIENT_HOOKS = [
47
- 'useState', 'useEffect', 'useLayoutEffect', 'useReducer', 'useRef',
48
- 'useImperativeHandle', 'useCallback', 'useMemo', 'useContext',
49
- 'useDebugValue', 'useDeferredValue', 'useTransition', 'useId',
50
- 'useSyncExternalStore', 'useInsertionEffect',
51
- ];
52
- function hasClientDirective(source) {
53
- const trimmed = source.trim();
54
- return trimmed.startsWith("'use client'") || trimmed.startsWith('"use client"');
55
- }
56
- function detectClientHooks(source) {
57
- const usedHooks = [];
58
- for (const hook of CLIENT_HOOKS) {
59
- const regex = new RegExp(`\\b${hook}\\s*[(<]`, 'g');
60
- if (regex.test(source)) {
61
- usedHooks.push(hook);
62
- }
63
- }
64
- // Check for event handlers
65
- if (/\bon[A-Z][a-zA-Z]*\s*=/g.test(source)) {
66
- usedHooks.push('event handlers');
67
- }
68
- return [...new Set(usedHooks)];
69
- }
44
+ const module_boundary_validator_1 = require("../server/module-boundary-validator");
70
45
  class VistaServerComponentPlugin {
71
46
  appDir;
47
+ componentsDir;
48
+ cacheComponentsEnabled;
72
49
  constructor(options) {
73
50
  this.appDir = options.appDir;
51
+ this.componentsDir = options.componentsDir;
52
+ this.cacheComponentsEnabled = Boolean(options.cacheComponentsEnabled);
74
53
  }
75
54
  apply(compiler) {
76
55
  // Use afterCompile hook so we can add errors to compilation
77
56
  compiler.hooks.afterCompile.tap('VistaServerComponentPlugin', (compilation) => {
78
- const errors = this.checkServerComponents();
57
+ const errors = (0, module_boundary_validator_1.validateModuleBoundaries)({
58
+ appDir: this.appDir,
59
+ extraRoots: this.componentsDir ? [this.componentsDir] : [],
60
+ cacheComponentsEnabled: this.cacheComponentsEnabled,
61
+ }).issues;
79
62
  if (errors.length > 0) {
80
63
  console.log('');
81
- console.log('\x1b[41m\x1b[37m ERROR \x1b[0m \x1b[31mServer Component Error\x1b[0m');
64
+ console.log('\x1b[41m\x1b[37m ERROR \x1b[0m \x1b[31mServer/Segment Validation Error\x1b[0m');
82
65
  console.log('');
83
66
  for (const error of errors) {
84
- console.log(`\x1b[31m✗\x1b[0m ${error.file}`);
85
- console.log(` You're using \x1b[33m${error.hooks.join(', ')}\x1b[0m in a Server Component.`);
86
- console.log('');
87
- console.log(` \x1b[36mTo fix:\x1b[0m Add \x1b[33m'use client'\x1b[0m at the top of your file:`);
88
- console.log('');
89
- console.log(` \x1b[32m'use client';\x1b[0m`);
67
+ const relativeFile = path.relative(this.appDir, error.filePath);
68
+ console.log(`\x1b[31m✗\x1b[0m ${relativeFile}`);
69
+ console.log(` ${error.message}`);
90
70
  console.log('');
71
+ if (error.fix) {
72
+ console.log(` \x1b[36mTo fix:\x1b[0m ${error.fix}`);
73
+ console.log('');
74
+ }
91
75
  // Add webpack error so it shows in overlay
92
76
  const WebpackError = require('webpack').WebpackError;
93
- const err = new WebpackError(`Server Component Error: ${error.file}\n` +
94
- `You're using ${error.hooks.join(', ')} in a Server Component.\n` +
95
- `Add 'use client' at the top of your file to make it a Client Component.`);
96
- err.file = error.file;
77
+ const err = new WebpackError(`${error.message}\n${error.fix ? `Fix: ${error.fix}` : ''}`.trim());
78
+ err.file = relativeFile;
97
79
  compilation.errors.push(err);
98
80
  }
99
81
  }
100
82
  });
101
83
  }
102
- checkServerComponents() {
103
- const errors = [];
104
- this.scanDirectory(this.appDir, errors);
105
- return errors;
106
- }
107
- scanDirectory(dir, errors) {
108
- if (!fs.existsSync(dir))
109
- return;
110
- const entries = fs.readdirSync(dir, { withFileTypes: true });
111
- for (const entry of entries) {
112
- const fullPath = path.join(dir, entry.name);
113
- if (entry.isDirectory()) {
114
- if (!entry.name.startsWith('.') && entry.name !== 'node_modules') {
115
- this.scanDirectory(fullPath, errors);
116
- }
117
- }
118
- else if (entry.isFile() && /\.(tsx?|jsx?)$/.test(entry.name)) {
119
- const source = fs.readFileSync(fullPath, 'utf-8');
120
- const isClient = hasClientDirective(source);
121
- const clientHooks = detectClientHooks(source);
122
- if (!isClient && clientHooks.length > 0) {
123
- errors.push({
124
- file: path.relative(this.appDir, fullPath),
125
- hooks: clientHooks
126
- });
127
- }
128
- }
129
- }
130
- }
131
84
  }
132
85
  exports.VistaServerComponentPlugin = VistaServerComponentPlugin;
133
86
  exports.default = VistaServerComponentPlugin;
@@ -1,6 +1,9 @@
1
1
  import webpack from 'webpack';
2
+ import type { VistaEngineVariant } from '../config';
2
3
  export interface WebpackConfigOptions {
3
4
  cwd: string;
4
5
  isDev: boolean;
6
+ engineVariant?: VistaEngineVariant;
7
+ cacheComponentsEnabled?: boolean;
5
8
  }
6
9
  export declare function createWebpackConfig(options: WebpackConfigOptions): webpack.Configuration;
@@ -12,8 +12,9 @@ const server_component_plugin_1 = require("./server-component-plugin");
12
12
  const vista_flight_plugin_1 = require("../build/webpack/plugins/vista-flight-plugin");
13
13
  const constants_1 = require("../constants");
14
14
  function createWebpackConfig(options) {
15
- const { cwd, isDev } = options;
15
+ const { cwd, isDev, engineVariant = 'default', cacheComponentsEnabled = false } = options;
16
16
  const vistaDir = path_1.default.join(cwd, constants_1.BUILD_DIR);
17
+ const flashDir = path_1.default.join(cwd, constants_1.FLASH_DIR);
17
18
  const entryPoint = path_1.default.join(vistaDir, 'client.tsx');
18
19
  // Find React - check local node_modules first, then traverse up for monorepo hoisting
19
20
  const findModulePath = (moduleName) => {
@@ -56,7 +57,9 @@ function createWebpackConfig(options) {
56
57
  cache: isDev
57
58
  ? {
58
59
  type: 'filesystem',
59
- cacheDirectory: path_1.default.join(cwd, 'node_modules', '.cache', 'vista-webpack'),
60
+ cacheDirectory: engineVariant === 'flashpack'
61
+ ? path_1.default.join(flashDir, 'cache', 'webpack')
62
+ : path_1.default.join(cwd, 'node_modules', '.cache', 'vista-webpack'),
60
63
  buildDependencies: {
61
64
  config: [__filename],
62
65
  },
@@ -143,7 +146,11 @@ function createWebpackConfig(options) {
143
146
  },
144
147
  plugins: [
145
148
  // Server Component enforcement - runs on every compile
146
- new server_component_plugin_1.VistaServerComponentPlugin({ appDir: path_1.default.join(cwd, 'app') }),
149
+ new server_component_plugin_1.VistaServerComponentPlugin({
150
+ appDir: path_1.default.join(cwd, 'app'),
151
+ componentsDir: path_1.default.join(cwd, 'components'),
152
+ cacheComponentsEnabled,
153
+ }),
147
154
  // Vista Flight Plugin - RSC bundle separation and manifest
148
155
  new vista_flight_plugin_1.VistaFlightPlugin({ appDir: path_1.default.join(cwd, 'app'), dev: isDev }),
149
156
  ...(isDev
@@ -156,6 +163,8 @@ function createWebpackConfig(options) {
156
163
  : []),
157
164
  new webpack_1.default.DefinePlugin({
158
165
  'process.env.NODE_ENV': JSON.stringify(isDev ? 'development' : 'production'),
166
+ 'process.env.VISTA_ENGINE': JSON.stringify(engineVariant),
167
+ 'process.env.VISTA_ENGINE_VARIANT': JSON.stringify(engineVariant),
159
168
  }),
160
169
  new mini_css_extract_plugin_1.default({
161
170
  filename: isDev ? 'modules.css' : 'modules-[contenthash:8].css',
@@ -3,6 +3,8 @@
3
3
  *
4
4
  * Generates build manifests, BUILD_ID, and manages .vista output structure.
5
5
  */
6
+ import type { VistaEngineVariant } from '../config';
7
+ import type { ImageConfig } from '../image/image-config';
6
8
  /**
7
9
  * Generate a unique build ID based on timestamp and random bytes.
8
10
  */
@@ -14,6 +16,7 @@ export declare function getBuildId(vistaDir: string, forceNew?: boolean): string
14
16
  export interface VistaDirs {
15
17
  root: string;
16
18
  cache: string;
19
+ imageCache: string;
17
20
  server: string;
18
21
  static: string;
19
22
  chunks: string;
@@ -48,6 +51,10 @@ export interface ArtifactManifest {
48
51
  requiredServerFiles: string;
49
52
  reactClientManifest: string;
50
53
  reactServerManifest: string;
54
+ serverManifest?: string;
55
+ runtimeManifest?: string;
56
+ fileTrace?: string;
57
+ standaloneServer?: string;
51
58
  };
52
59
  }
53
60
  /**
@@ -61,10 +68,16 @@ interface RouteLike {
61
68
  }
62
69
  export declare function generateAppPathRoutesManifest(vistaDir: string, routes?: RouteLike[]): Record<string, string>;
63
70
  export declare function generatePrerenderManifest(vistaDir: string): void;
64
- export declare function generateRequiredServerFilesManifest(cwd: string, vistaDir: string): void;
71
+ export declare function generateRequiredServerFilesManifest(cwd: string, vistaDir: string, extraFiles?: string[], appDir?: string): void;
65
72
  export declare function ensureJsonFile(vistaDir: string, relativePath: string, fallback?: unknown): void;
66
- export declare function writeArtifactManifest(vistaDir: string, buildId: string): ArtifactManifest;
73
+ export declare function writeArtifactManifest(vistaDir: string, buildId: string, extraManifestEntries?: Partial<ArtifactManifest['manifests']>): ArtifactManifest;
67
74
  export declare function writeCanonicalVistaArtifacts(cwd: string, vistaDir: string, buildId: string, routes?: RouteLike[]): ArtifactManifest;
75
+ interface WriteReservedVistaArtifactsOptions {
76
+ buildId: string;
77
+ engineVariant?: VistaEngineVariant;
78
+ imagesConfig?: Partial<ImageConfig> | undefined;
79
+ }
80
+ export declare function writeReservedVistaArtifacts(vistaDir: string, options: WriteReservedVistaArtifactsOptions): void;
68
81
  export interface RouteInfo {
69
82
  page: string;
70
83
  regex: string;
@@ -109,7 +122,7 @@ export declare function generateServerComponentsManifest(vistaDir: string, serve
109
122
  /**
110
123
  * Get Webpack cache configuration for persistent caching.
111
124
  */
112
- export declare function getWebpackCacheConfig(vistaDir: string, buildId: string, name: string): {
125
+ export declare function getWebpackCacheConfig(vistaDir: string, buildId: string, name: string, engineVariant?: VistaEngineVariant, cwd?: string): {
113
126
  type: "filesystem";
114
127
  version: string;
115
128
  cacheDirectory: string;
@@ -122,4 +135,5 @@ export declare function getWebpackCacheConfig(vistaDir: string, buildId: string,
122
135
  * Clean old cache entries (keeps last N builds).
123
136
  */
124
137
  export declare function cleanOldCache(vistaDir: string, keepBuilds?: number): void;
138
+ export declare function pruneEmptyVistaDirectories(vistaDir: string): void;
125
139
  export {};
@@ -18,11 +18,13 @@ exports.generateRequiredServerFilesManifest = generateRequiredServerFilesManifes
18
18
  exports.ensureJsonFile = ensureJsonFile;
19
19
  exports.writeArtifactManifest = writeArtifactManifest;
20
20
  exports.writeCanonicalVistaArtifacts = writeCanonicalVistaArtifacts;
21
+ exports.writeReservedVistaArtifacts = writeReservedVistaArtifacts;
21
22
  exports.generateRoutesManifest = generateRoutesManifest;
22
23
  exports.generateClientComponentsManifest = generateClientComponentsManifest;
23
24
  exports.generateServerComponentsManifest = generateServerComponentsManifest;
24
25
  exports.getWebpackCacheConfig = getWebpackCacheConfig;
25
26
  exports.cleanOldCache = cleanOldCache;
27
+ exports.pruneEmptyVistaDirectories = pruneEmptyVistaDirectories;
26
28
  const fs_1 = __importDefault(require("fs"));
27
29
  const path_1 = __importDefault(require("path"));
28
30
  const crypto_1 = __importDefault(require("crypto"));
@@ -62,6 +64,7 @@ function createVistaDirectories(cwd, mode = 'legacy') {
62
64
  const dirs = {
63
65
  root,
64
66
  cache: path_1.default.join(root, 'cache'),
67
+ imageCache: path_1.default.join(root, 'cache', 'images'),
65
68
  server: path_1.default.join(root, 'server'),
66
69
  static: path_1.default.join(root, 'static'),
67
70
  chunks: path_1.default.join(root, 'static', 'chunks'),
@@ -71,19 +74,9 @@ function createVistaDirectories(cwd, mode = 'legacy') {
71
74
  // Always create root
72
75
  fs_1.default.mkdirSync(root, { recursive: true });
73
76
  if (mode === 'rsc') {
74
- // RSC mode: create only currently-used directories.
75
- // Keep css/media paths reserved in `dirs` for future use, but do not
76
- // create empty folders unless the build actually emits files there.
77
- [dirs.root, dirs.cache, dirs.server, dirs.static, dirs.chunks].forEach((dir) => {
77
+ [dirs.root, dirs.cache, dirs.imageCache, dirs.server, dirs.static, dirs.chunks, dirs.media].forEach((dir) => {
78
78
  fs_1.default.mkdirSync(dir, { recursive: true });
79
79
  });
80
- // Cache subdirectories
81
- fs_1.default.mkdirSync(path_1.default.join(dirs.cache, 'webpack'), { recursive: true });
82
- fs_1.default.mkdirSync(path_1.default.join(dirs.cache, 'swc'), { recursive: true });
83
- fs_1.default.mkdirSync(path_1.default.join(dirs.cache, 'images'), { recursive: true });
84
- // Server subdirectories
85
- fs_1.default.mkdirSync(path_1.default.join(dirs.server, 'app'), { recursive: true });
86
- fs_1.default.mkdirSync(path_1.default.join(dirs.server, 'chunks'), { recursive: true });
87
80
  }
88
81
  // Legacy mode: only root dir is created — webpack outputs directly into .vista/
89
82
  return dirs;
@@ -159,18 +152,21 @@ function generatePrerenderManifest(vistaDir) {
159
152
  };
160
153
  fs_1.default.writeFileSync(path_1.default.join(vistaDir, 'prerender-manifest.json'), JSON.stringify(manifest, null, 2));
161
154
  }
162
- function generateRequiredServerFilesManifest(cwd, vistaDir) {
155
+ function generateRequiredServerFilesManifest(cwd, vistaDir, extraFiles = [], appDir = cwd) {
156
+ const files = Array.from(new Set([
157
+ `${constants_1.BUILD_DIR}/BUILD_ID`,
158
+ `${constants_1.BUILD_DIR}/build-manifest.json`,
159
+ `${constants_1.BUILD_DIR}/routes-manifest.json`,
160
+ `${constants_1.BUILD_DIR}/app-path-routes-manifest.json`,
161
+ `${constants_1.BUILD_DIR}/server/server-manifest.json`,
162
+ ...extraFiles,
163
+ ]));
163
164
  const manifest = {
164
165
  version: 1,
165
166
  config: {},
166
- appDir: cwd,
167
- relativeAppDir: '.',
168
- files: [
169
- `${constants_1.BUILD_DIR}/BUILD_ID`,
170
- `${constants_1.BUILD_DIR}/build-manifest.json`,
171
- `${constants_1.BUILD_DIR}/routes-manifest.json`,
172
- `${constants_1.BUILD_DIR}/app-path-routes-manifest.json`,
173
- ],
167
+ appDir,
168
+ relativeAppDir: path_1.default.relative(cwd, appDir) || '.',
169
+ files,
174
170
  };
175
171
  fs_1.default.writeFileSync(path_1.default.join(vistaDir, 'required-server-files.json'), JSON.stringify(manifest, null, 2));
176
172
  }
@@ -180,7 +176,7 @@ function ensureJsonFile(vistaDir, relativePath, fallback = {}) {
180
176
  fs_1.default.writeFileSync(absolutePath, JSON.stringify(fallback, null, 2));
181
177
  }
182
178
  }
183
- function writeArtifactManifest(vistaDir, buildId) {
179
+ function writeArtifactManifest(vistaDir, buildId, extraManifestEntries = {}) {
184
180
  const artifactManifest = {
185
181
  schemaVersion: 1,
186
182
  buildId,
@@ -194,6 +190,7 @@ function writeArtifactManifest(vistaDir, buildId) {
194
190
  requiredServerFiles: 'required-server-files.json',
195
191
  reactClientManifest: 'react-client-manifest.json',
196
192
  reactServerManifest: 'react-server-manifest.json',
193
+ ...extraManifestEntries,
197
194
  },
198
195
  };
199
196
  fs_1.default.writeFileSync(path_1.default.join(vistaDir, 'artifact-manifest.json'), JSON.stringify(artifactManifest, null, 2));
@@ -212,6 +209,59 @@ function writeCanonicalVistaArtifacts(cwd, vistaDir, buildId, routes = []) {
212
209
  ensureJsonFile(vistaDir, 'react-server-manifest.json', {});
213
210
  return writeArtifactManifest(vistaDir, buildId);
214
211
  }
212
+ function writeReservedVistaArtifacts(vistaDir, options) {
213
+ const engineVariant = options.engineVariant || 'default';
214
+ const generatedAt = new Date().toISOString();
215
+ const cacheDir = path_1.default.join(vistaDir, 'cache');
216
+ const imageCacheDir = path_1.default.join(cacheDir, 'images');
217
+ const mediaDir = path_1.default.join(vistaDir, 'static', 'media');
218
+ fs_1.default.mkdirSync(cacheDir, { recursive: true });
219
+ fs_1.default.mkdirSync(imageCacheDir, { recursive: true });
220
+ fs_1.default.mkdirSync(mediaDir, { recursive: true });
221
+ fs_1.default.writeFileSync(path_1.default.join(cacheDir, 'cache-manifest.json'), JSON.stringify({
222
+ schemaVersion: 1,
223
+ buildId: options.buildId,
224
+ generatedAt,
225
+ engine: engineVariant,
226
+ activeCacheRoot: engineVariant === 'flashpack' ? '.flash/cache' : '.vista/cache/webpack',
227
+ directories: {
228
+ localCache: '.vista/cache',
229
+ webpack: engineVariant === 'flashpack' ? '.flash/cache/webpack' : '.vista/cache/webpack',
230
+ images: '.vista/cache/images',
231
+ },
232
+ notes: [
233
+ engineVariant === 'flashpack'
234
+ ? 'Flashpack stores its hot build cache in .flash while .vista/cache keeps framework metadata.'
235
+ : 'Default engine stores framework metadata here and may add webpack cache artifacts during rebuilds.',
236
+ ],
237
+ }, null, 2));
238
+ fs_1.default.writeFileSync(path_1.default.join(imageCacheDir, 'manifest.json'), JSON.stringify({
239
+ schemaVersion: 1,
240
+ buildId: options.buildId,
241
+ generatedAt,
242
+ endpoint: constants_1.IMAGE_ENDPOINT,
243
+ cacheDirectory: '.vista/cache/images',
244
+ config: options.imagesConfig || {},
245
+ behavior: {
246
+ optimization: 'on-demand',
247
+ staticImportsEmitInto: '.vista/static/media',
248
+ publicReferencesStayIn: 'public/',
249
+ },
250
+ }, null, 2));
251
+ const emittedMedia = fs_1.default
252
+ .readdirSync(mediaDir, { withFileTypes: true })
253
+ .filter((entry) => entry.isFile() && entry.name !== 'media-manifest.json')
254
+ .map((entry) => entry.name)
255
+ .sort();
256
+ fs_1.default.writeFileSync(path_1.default.join(mediaDir, 'media-manifest.json'), JSON.stringify({
257
+ schemaVersion: 1,
258
+ buildId: options.buildId,
259
+ generatedAt,
260
+ mediaDirectory: '.vista/static/media',
261
+ emittedFiles: emittedMedia,
262
+ note: 'This directory is reserved for emitted media assets. Public file references are served from public/ and may leave this list empty.',
263
+ }, null, 2));
264
+ }
215
265
  /**
216
266
  * Generate routes-manifest.json from route tree.
217
267
  */
@@ -257,11 +307,14 @@ function generateServerComponentsManifest(vistaDir, serverModules = {}) {
257
307
  /**
258
308
  * Get Webpack cache configuration for persistent caching.
259
309
  */
260
- function getWebpackCacheConfig(vistaDir, buildId, name) {
310
+ function getWebpackCacheConfig(vistaDir, buildId, name, engineVariant = 'default', cwd = process.cwd()) {
311
+ const cacheDirectory = engineVariant === 'flashpack'
312
+ ? path_1.default.join(cwd, constants_1.FLASH_DIR, 'cache', 'webpack')
313
+ : path_1.default.join(vistaDir, 'cache', 'webpack');
261
314
  return {
262
315
  type: 'filesystem',
263
316
  version: buildId,
264
- cacheDirectory: path_1.default.join(vistaDir, 'cache', 'webpack'),
317
+ cacheDirectory,
265
318
  name: name,
266
319
  buildDependencies: {
267
320
  config: [__filename],
@@ -289,3 +342,26 @@ function cleanOldCache(vistaDir, keepBuilds = 5) {
289
342
  fs_1.default.rmSync(entry.path, { recursive: true, force: true });
290
343
  });
291
344
  }
345
+ function pruneEmptyVistaDirectories(vistaDir) {
346
+ if (!fs_1.default.existsSync(vistaDir))
347
+ return;
348
+ const prune = (absolutePath) => {
349
+ const entries = fs_1.default.readdirSync(absolutePath, { withFileTypes: true });
350
+ for (const entry of entries) {
351
+ if (!entry.isDirectory())
352
+ continue;
353
+ const childPath = path_1.default.join(absolutePath, entry.name);
354
+ prune(childPath);
355
+ }
356
+ // Never remove the root .vista directory itself.
357
+ if (absolutePath === vistaDir)
358
+ return false;
359
+ const remaining = fs_1.default.readdirSync(absolutePath);
360
+ if (remaining.length === 0) {
361
+ fs_1.default.rmdirSync(absolutePath);
362
+ return true;
363
+ }
364
+ return false;
365
+ };
366
+ prune(vistaDir);
367
+ }
@@ -7,11 +7,13 @@
7
7
  */
8
8
  import webpack from 'webpack';
9
9
  import { VistaDirs } from '../manifest';
10
+ import type { VistaEngineVariant } from '../../config';
10
11
  export interface RSCCompilerOptions {
11
12
  cwd: string;
12
13
  isDev: boolean;
13
14
  vistaDirs: VistaDirs;
14
15
  buildId: string;
16
+ engineVariant?: VistaEngineVariant;
15
17
  clientReferenceFiles?: string[];
16
18
  }
17
19
  /**
@@ -19,6 +19,7 @@ const fs_1 = __importDefault(require("fs"));
19
19
  const manifest_1 = require("../manifest");
20
20
  const client_manifest_1 = require("./client-manifest");
21
21
  const server_manifest_1 = require("./server-manifest");
22
+ const react_client_reference_manifest_1 = require("./react-client-reference-manifest");
22
23
  const constants_1 = require("../../constants");
23
24
  // Find module path (handles monorepo hoisting)
24
25
  const findModulePath = (moduleName, cwd) => {
@@ -59,7 +60,7 @@ function resolveFromWorkspace(specifier, cwd) {
59
60
  * Output goes to .vista/server/ and is NEVER sent to the client.
60
61
  */
61
62
  function createServerWebpackConfig(options) {
62
- const { cwd, isDev, vistaDirs, buildId } = options;
63
+ const { cwd, isDev, vistaDirs, buildId, engineVariant = 'default' } = options;
63
64
  const swcLoaderPath = resolveFromWorkspace('swc-loader', cwd);
64
65
  const nullLoaderPath = resolveFromWorkspace('null-loader', cwd);
65
66
  const cssLoaderPath = resolveFromWorkspace('css-loader', cwd);
@@ -119,7 +120,9 @@ function createServerWebpackConfig(options) {
119
120
  callback();
120
121
  },
121
122
  ],
122
- cache: isDev ? (0, manifest_1.getWebpackCacheConfig)(vistaDirs.root, buildId, 'server-development') : false,
123
+ cache: isDev
124
+ ? (0, manifest_1.getWebpackCacheConfig)(vistaDirs.root, buildId, 'server-development', engineVariant, cwd)
125
+ : false,
123
126
  resolve: {
124
127
  extensions: ['.tsx', '.ts', '.jsx', '.js'],
125
128
  modules: [path_1.default.resolve(cwd, 'node_modules'), 'node_modules'],
@@ -175,6 +178,8 @@ function createServerWebpackConfig(options) {
175
178
  plugins: [
176
179
  new webpack_1.default.DefinePlugin({
177
180
  'process.env.NODE_ENV': JSON.stringify(isDev ? 'development' : 'production'),
181
+ 'process.env.VISTA_ENGINE': JSON.stringify(engineVariant),
182
+ 'process.env.VISTA_ENGINE_VARIANT': JSON.stringify(engineVariant),
178
183
  [constants_1.BUILD_ID_DEFINE]: JSON.stringify(buildId),
179
184
  [constants_1.SERVER_DEFINE]: 'true',
180
185
  }),
@@ -190,7 +195,7 @@ function createServerWebpackConfig(options) {
190
195
  * Server components are replaced with client references.
191
196
  */
192
197
  function createClientWebpackConfig(options) {
193
- const { cwd, isDev, vistaDirs, buildId, clientReferenceFiles = [] } = options;
198
+ const { cwd, isDev, vistaDirs, buildId, engineVariant = 'default', clientReferenceFiles = [] } = options;
194
199
  const swcLoaderPath = resolveFromWorkspace('swc-loader', cwd);
195
200
  const nullLoaderPath = resolveFromWorkspace('null-loader', cwd);
196
201
  const cssLoaderPath = resolveFromWorkspace('css-loader', cwd);
@@ -343,14 +348,26 @@ function createClientWebpackConfig(options) {
343
348
  // and preloadModule with the chunks array).
344
349
  {
345
350
  apply(compiler) {
346
- compiler.hooks.make.tap('VistaSSRManifestPatch', (compilation) => {
351
+ compiler.hooks.make.tap('VistaFlightManifestPatch', (compilation) => {
347
352
  compilation.hooks.processAssets.tap({
348
- name: 'VistaSSRManifestPatch',
353
+ name: 'VistaFlightManifestPatch',
349
354
  // Run after the Flight plugin (REPORT stage) has emitted assets
350
355
  stage: webpack_1.default.Compilation.PROCESS_ASSETS_STAGE_REPORT + 1,
351
356
  }, () => {
357
+ const clientAssetName = '../../react-client-manifest.json';
352
358
  const ssrAssetName = '../../react-server-manifest.json';
359
+ const clientAsset = compilation.getAsset(clientAssetName);
353
360
  const ssrAsset = compilation.getAsset(ssrAssetName);
361
+ if (clientAsset) {
362
+ try {
363
+ const manifest = JSON.parse(clientAsset.source.source().toString());
364
+ const normalized = (0, react_client_reference_manifest_1.normalizeReactClientReferenceManifest)(manifest);
365
+ compilation.updateAsset(clientAssetName, new webpack_1.default.sources.RawSource(JSON.stringify(normalized, null, 2), false));
366
+ }
367
+ catch {
368
+ // If parsing fails, leave the asset as-is
369
+ }
370
+ }
354
371
  if (!ssrAsset)
355
372
  return;
356
373
  try {
@@ -372,6 +389,7 @@ function createClientWebpackConfig(options) {
372
389
  }
373
390
  }
374
391
  }
392
+ (0, react_client_reference_manifest_1.normalizeReactServerConsumerManifest)(manifest);
375
393
  compilation.updateAsset(ssrAssetName, new webpack_1.default.sources.RawSource(JSON.stringify(manifest, null, 2), false));
376
394
  }
377
395
  }
@@ -384,6 +402,8 @@ function createClientWebpackConfig(options) {
384
402
  },
385
403
  new webpack_1.default.DefinePlugin({
386
404
  'process.env.NODE_ENV': JSON.stringify(isDev ? 'development' : 'production'),
405
+ 'process.env.VISTA_ENGINE': JSON.stringify(engineVariant),
406
+ 'process.env.VISTA_ENGINE_VARIANT': JSON.stringify(engineVariant),
387
407
  [constants_1.BUILD_ID_DEFINE]: JSON.stringify(buildId),
388
408
  [constants_1.SERVER_DEFINE]: 'false',
389
409
  }),
@@ -0,0 +1,22 @@
1
+ export interface ReactClientReferenceManifestEntry {
2
+ id: string | number;
3
+ chunks: Array<string | number>;
4
+ name: string;
5
+ }
6
+ export type ReactClientReferenceManifest = Record<string, ReactClientReferenceManifestEntry>;
7
+ export interface ReactServerConsumerManifestEntry {
8
+ specifier?: string;
9
+ id?: string | number;
10
+ chunks?: Array<string | number>;
11
+ name?: string;
12
+ }
13
+ export interface ReactServerConsumerManifest {
14
+ moduleLoading?: {
15
+ prefix: string;
16
+ crossOrigin: string | null;
17
+ };
18
+ moduleMap?: Record<string, Record<string, ReactServerConsumerManifestEntry>>;
19
+ serverModuleMap?: Record<string, unknown>;
20
+ }
21
+ export declare function normalizeReactClientReferenceManifest(input: ReactClientReferenceManifest): ReactClientReferenceManifest;
22
+ export declare function normalizeReactServerConsumerManifest(input: ReactServerConsumerManifest): ReactServerConsumerManifest;