@vistagenic/vista 0.1.0-alpha.1

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 (100) hide show
  1. package/bin/vista.js +98 -0
  2. package/dist/auth/index.d.ts +8 -0
  3. package/dist/auth/index.js +16 -0
  4. package/dist/bin/build-rsc.d.ts +17 -0
  5. package/dist/bin/build-rsc.js +320 -0
  6. package/dist/bin/build.d.ts +4 -0
  7. package/dist/bin/build.js +336 -0
  8. package/dist/bin/file-scanner.d.ts +66 -0
  9. package/dist/bin/file-scanner.js +399 -0
  10. package/dist/bin/server-component-plugin.d.ts +17 -0
  11. package/dist/bin/server-component-plugin.js +133 -0
  12. package/dist/bin/webpack.config.d.ts +6 -0
  13. package/dist/bin/webpack.config.js +138 -0
  14. package/dist/build/manifest.d.ts +95 -0
  15. package/dist/build/manifest.js +168 -0
  16. package/dist/build/rsc/client-manifest.d.ts +48 -0
  17. package/dist/build/rsc/client-manifest.js +191 -0
  18. package/dist/build/rsc/client-reference-plugin.d.ts +37 -0
  19. package/dist/build/rsc/client-reference-plugin.js +185 -0
  20. package/dist/build/rsc/compiler.d.ts +36 -0
  21. package/dist/build/rsc/compiler.js +311 -0
  22. package/dist/build/rsc/index.d.ts +16 -0
  23. package/dist/build/rsc/index.js +32 -0
  24. package/dist/build/rsc/native-scanner.d.ts +123 -0
  25. package/dist/build/rsc/native-scanner.js +165 -0
  26. package/dist/build/rsc/rsc-renderer.d.ts +99 -0
  27. package/dist/build/rsc/rsc-renderer.js +269 -0
  28. package/dist/build/rsc/server-component-loader.d.ts +19 -0
  29. package/dist/build/rsc/server-component-loader.js +147 -0
  30. package/dist/build/rsc/server-manifest.d.ts +63 -0
  31. package/dist/build/rsc/server-manifest.js +268 -0
  32. package/dist/build/webpack/loaders/vista-flight-loader.d.ts +17 -0
  33. package/dist/build/webpack/loaders/vista-flight-loader.js +93 -0
  34. package/dist/build/webpack/plugins/vista-flight-plugin.d.ts +36 -0
  35. package/dist/build/webpack/plugins/vista-flight-plugin.js +133 -0
  36. package/dist/client/dynamic.d.ts +25 -0
  37. package/dist/client/dynamic.js +68 -0
  38. package/dist/client/font.d.ts +98 -0
  39. package/dist/client/font.js +109 -0
  40. package/dist/client/head.d.ts +79 -0
  41. package/dist/client/head.js +261 -0
  42. package/dist/client/hydration.d.ts +45 -0
  43. package/dist/client/hydration.js +291 -0
  44. package/dist/client/link.d.ts +30 -0
  45. package/dist/client/link.js +188 -0
  46. package/dist/client/navigation.d.ts +28 -0
  47. package/dist/client/navigation.js +116 -0
  48. package/dist/client/router.d.ts +41 -0
  49. package/dist/client/router.js +190 -0
  50. package/dist/client/script.d.ts +51 -0
  51. package/dist/client/script.js +118 -0
  52. package/dist/components/client-island.d.ts +34 -0
  53. package/dist/components/client-island.js +75 -0
  54. package/dist/components/client.d.ts +29 -0
  55. package/dist/components/client.js +102 -0
  56. package/dist/components/index.d.ts +1 -0
  57. package/dist/components/index.js +8 -0
  58. package/dist/components/link.d.ts +6 -0
  59. package/dist/components/link.js +13 -0
  60. package/dist/config.d.ts +10 -0
  61. package/dist/config.js +31 -0
  62. package/dist/dev-error.d.ts +35 -0
  63. package/dist/dev-error.js +310 -0
  64. package/dist/image/get-img-props.d.ts +28 -0
  65. package/dist/image/get-img-props.js +49 -0
  66. package/dist/image/image-config.d.ts +20 -0
  67. package/dist/image/image-config.js +20 -0
  68. package/dist/image/image-loader.d.ts +7 -0
  69. package/dist/image/image-loader.js +14 -0
  70. package/dist/image/index.d.ts +6 -0
  71. package/dist/image/index.js +110 -0
  72. package/dist/image.d.ts +10 -0
  73. package/dist/image.js +7 -0
  74. package/dist/index.d.ts +20 -0
  75. package/dist/index.js +53 -0
  76. package/dist/metadata/generate.d.ts +22 -0
  77. package/dist/metadata/generate.js +324 -0
  78. package/dist/metadata/index.d.ts +7 -0
  79. package/dist/metadata/index.js +26 -0
  80. package/dist/metadata/types.d.ts +325 -0
  81. package/dist/metadata/types.js +15 -0
  82. package/dist/router/context.d.ts +8 -0
  83. package/dist/router/context.js +13 -0
  84. package/dist/router/index.d.ts +2 -0
  85. package/dist/router/index.js +18 -0
  86. package/dist/router/provider.d.ts +5 -0
  87. package/dist/router/provider.js +31 -0
  88. package/dist/server/client-boundary.d.ts +48 -0
  89. package/dist/server/client-boundary.js +133 -0
  90. package/dist/server/engine.d.ts +4 -0
  91. package/dist/server/engine.js +651 -0
  92. package/dist/server/index.d.ts +95 -0
  93. package/dist/server/index.js +177 -0
  94. package/dist/server/rsc-engine.d.ts +20 -0
  95. package/dist/server/rsc-engine.js +588 -0
  96. package/dist/server/rsc-module-system.d.ts +33 -0
  97. package/dist/server/rsc-module-system.js +119 -0
  98. package/dist/types/index.d.ts +4 -0
  99. package/dist/types/index.js +2 -0
  100. package/package.json +103 -0
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ /**
3
+ * Vista Server Component Loader
4
+ *
5
+ * Webpack loader that transforms server component imports in client bundles.
6
+ *
7
+ * When a server component is imported in a client bundle:
8
+ * 1. The loader detects if the file has 'client load' directive
9
+ * 2. If NOT a client component, replace the module with a proxy
10
+ * 3. The proxy provides helpful error messages when misused
11
+ */
12
+ var __importDefault = (this && this.__importDefault) || function (mod) {
13
+ return (mod && mod.__esModule) ? mod : { "default": mod };
14
+ };
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.default = serverComponentLoader;
17
+ const path_1 = __importDefault(require("path"));
18
+ /**
19
+ * Check if source has 'client load' directive
20
+ */
21
+ function hasClientDirective(source) {
22
+ const trimmed = source.trim();
23
+ return trimmed.startsWith("'client load'") || trimmed.startsWith('"client load"');
24
+ }
25
+ /**
26
+ * Extract the component name from exports
27
+ */
28
+ function extractComponentName(source) {
29
+ // Try to find "export default function ComponentName" or "export default ComponentName"
30
+ const defaultFuncMatch = source.match(/export\s+default\s+function\s+([A-Z][a-zA-Z0-9_]*)/);
31
+ if (defaultFuncMatch)
32
+ return defaultFuncMatch[1];
33
+ const defaultClassMatch = source.match(/export\s+default\s+class\s+([A-Z][a-zA-Z0-9_]*)/);
34
+ if (defaultClassMatch)
35
+ return defaultClassMatch[1];
36
+ const defaultConstMatch = source.match(/export\s+default\s+([A-Z][a-zA-Z0-9_]*)/);
37
+ if (defaultConstMatch)
38
+ return defaultConstMatch[1];
39
+ return 'ServerComponent';
40
+ }
41
+ /**
42
+ * Server Component Loader
43
+ */
44
+ function serverComponentLoader(source) {
45
+ const options = this.getOptions();
46
+ const resourcePath = this.resourcePath;
47
+ // Only process files in the app directory
48
+ if (!resourcePath.startsWith(options.appDir)) {
49
+ return source;
50
+ }
51
+ // If this IS a client component, pass through unchanged
52
+ if (hasClientDirective(source)) {
53
+ return source;
54
+ }
55
+ // This is a server component - we need to check how it's being used
56
+ //
57
+ // The key insight: we're building the CLIENT bundle here.
58
+ // Server components should NOT be in the client bundle at all.
59
+ //
60
+ // However, there are valid use cases:
61
+ // 1. A client component might import a server component's TYPE only
62
+ // 2. A server component might be passed as children (rendered server-side)
63
+ //
64
+ // For safety, we replace the module with a proxy that:
65
+ // - Exports a function that throws a helpful error
66
+ // - Has a special marker so the RSC renderer can handle it
67
+ const relativePath = path_1.default.relative(options.appDir, resourcePath);
68
+ const componentId = `server:${relativePath.replace(/\\/g, '/').replace(/\.[jt]sx?$/, '')}`;
69
+ const componentName = extractComponentName(source);
70
+ // Generate proxy module
71
+ const proxyModule = `
72
+ // Vista Server Component Proxy
73
+ // This file was transformed because "${relativePath}" is a Server Component
74
+ // Server Components cannot be rendered on the client.
75
+
76
+ import * as React from 'react';
77
+
78
+ const componentId = ${JSON.stringify(componentId)};
79
+ const componentName = ${JSON.stringify(componentName)};
80
+
81
+ function ServerComponentError(props) {
82
+ if (typeof window !== 'undefined') {
83
+ console.error(
84
+ \`[Vista RSC] Attempted to render server component "\${componentName}" on the client.\`,
85
+ \`\\nServer components can only be rendered on the server.\`,
86
+ \`\\nTo fix: add 'client load' at the top of the file if you need client-side interactivity.\`
87
+ );
88
+ }
89
+
90
+ // In development, show an error UI
91
+ if (process.env.NODE_ENV === 'development') {
92
+ return React.createElement('div', {
93
+ style: {
94
+ padding: '20px',
95
+ background: '#fee2e2',
96
+ border: '2px solid #ef4444',
97
+ borderRadius: '8px',
98
+ color: '#991b1b',
99
+ fontFamily: 'monospace',
100
+ }
101
+ }, [
102
+ React.createElement('h3', { key: 'title', style: { margin: '0 0 10px 0' } }, '⚠️ Server Component Error'),
103
+ React.createElement('p', { key: 'msg', style: { margin: '0 0 10px 0' } },
104
+ \`Component "\${componentName}" is a Server Component and cannot be rendered on the client.\`
105
+ ),
106
+ React.createElement('p', { key: 'fix', style: { margin: 0, fontSize: '12px' } },
107
+ "Add 'client load' at the top of the file to make it a Client Component."
108
+ ),
109
+ ]);
110
+ }
111
+
112
+ // In production, render nothing (the server should have rendered it)
113
+ return null;
114
+ }
115
+
116
+ // Mark as server component reference
117
+ ServerComponentError.$$typeof = Symbol.for('vista.server.reference');
118
+ ServerComponentError.$$id = componentId;
119
+ ServerComponentError.$$name = componentName;
120
+
121
+ // Re-export any named exports as proxies too
122
+ ${extractNamedExports(source)
123
+ .map((name) => `
124
+ export const ${name} = ServerComponentError;
125
+ `)
126
+ .join('\n')}
127
+
128
+ export default ServerComponentError;
129
+ `;
130
+ return proxyModule;
131
+ }
132
+ /**
133
+ * Extract named exports from source
134
+ */
135
+ function extractNamedExports(source) {
136
+ const exports = [];
137
+ // Match: export const/let/var Name, export function Name, export class Name
138
+ const namedRegex = /export\s+(?:const|let|var|function|class)\s+([A-Z][a-zA-Z0-9_]*)/g;
139
+ let match;
140
+ while ((match = namedRegex.exec(source)) !== null) {
141
+ exports.push(match[1]);
142
+ }
143
+ return exports;
144
+ }
145
+ // Also export the raw loader for Webpack
146
+ module.exports = serverComponentLoader;
147
+ module.exports.default = serverComponentLoader;
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Server Component Manifest Generator
3
+ *
4
+ * Scans the app directory and builds a manifest of all Server Components.
5
+ * Server components are all components WITHOUT 'client load' directive.
6
+ *
7
+ * Server components:
8
+ * - Render on the server only
9
+ * - Have access to server resources (DB, file system, env vars)
10
+ * - Contribute 0kb to the client JavaScript bundle
11
+ */
12
+ export interface ServerComponentEntry {
13
+ /** Unique ID for this component */
14
+ id: string;
15
+ /** Relative path from app directory */
16
+ path: string;
17
+ /** Absolute file path */
18
+ absolutePath: string;
19
+ /** Component type: page, layout, loading, error, component */
20
+ type: 'page' | 'layout' | 'loading' | 'error' | 'not-found' | 'component';
21
+ /** Has static metadata export */
22
+ hasMetadata: boolean;
23
+ /** Has generateMetadata function */
24
+ hasGenerateMetadata: boolean;
25
+ /** List of client components this server component imports */
26
+ clientDependencies: string[];
27
+ }
28
+ export interface ServerManifest {
29
+ /** Build ID */
30
+ buildId: string;
31
+ /** Map of module ID to server component info */
32
+ serverModules: Record<string, ServerComponentEntry>;
33
+ /** Map of path to module ID */
34
+ pathToId: Record<string, string>;
35
+ /** Routes discovered */
36
+ routes: RouteEntry[];
37
+ }
38
+ export interface RouteEntry {
39
+ /** URL path pattern */
40
+ pattern: string;
41
+ /** Page component path */
42
+ pagePath: string;
43
+ /** Layout component paths (from root to this route) */
44
+ layoutPaths: string[];
45
+ /** Loading component path if exists */
46
+ loadingPath?: string;
47
+ /** Error component path if exists */
48
+ errorPath?: string;
49
+ /** Route type */
50
+ type: 'static' | 'dynamic' | 'catch-all';
51
+ }
52
+ /**
53
+ * Generate the server component manifest
54
+ */
55
+ export declare function generateServerManifest(cwd: string, appDir: string): ServerManifest;
56
+ /**
57
+ * Get server component by path
58
+ */
59
+ export declare function getServerComponent(manifest: ServerManifest, filePath: string): ServerComponentEntry | undefined;
60
+ /**
61
+ * Check if a path is a server component
62
+ */
63
+ export declare function isServerComponentPath(manifest: ServerManifest, filePath: string): boolean;
@@ -0,0 +1,268 @@
1
+ "use strict";
2
+ /**
3
+ * Server Component Manifest Generator
4
+ *
5
+ * Scans the app directory and builds a manifest of all Server Components.
6
+ * Server components are all components WITHOUT 'client load' directive.
7
+ *
8
+ * Server components:
9
+ * - Render on the server only
10
+ * - Have access to server resources (DB, file system, env vars)
11
+ * - Contribute 0kb to the client JavaScript bundle
12
+ */
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.generateServerManifest = generateServerManifest;
18
+ exports.getServerComponent = getServerComponent;
19
+ exports.isServerComponentPath = isServerComponentPath;
20
+ const fs_1 = __importDefault(require("fs"));
21
+ const path_1 = __importDefault(require("path"));
22
+ // Try to load Rust NAPI bindings
23
+ let rustNative = null;
24
+ try {
25
+ const possiblePaths = [
26
+ path_1.default.resolve(__dirname, '../../../../../crates/vista-napi'),
27
+ path_1.default.resolve(__dirname, '../../../../crates/vista-napi'),
28
+ ];
29
+ for (const p of possiblePaths) {
30
+ try {
31
+ rustNative = require(p);
32
+ break;
33
+ }
34
+ catch (e) {
35
+ // Try next
36
+ }
37
+ }
38
+ }
39
+ catch (e) {
40
+ // Fallback to JS
41
+ }
42
+ /**
43
+ * Check if source has 'client load' directive
44
+ */
45
+ function hasClientDirective(source) {
46
+ if (rustNative?.isClientComponent) {
47
+ return rustNative.isClientComponent(source);
48
+ }
49
+ const trimmed = source.trim();
50
+ return trimmed.startsWith("'client load'") || trimmed.startsWith('"client load"');
51
+ }
52
+ /**
53
+ * Check for metadata exports
54
+ */
55
+ function analyzeMetadata(source) {
56
+ if (rustNative?.analyzeMetadata) {
57
+ const result = rustNative.analyzeMetadata(source);
58
+ return {
59
+ hasMetadata: result.has_static_metadata,
60
+ hasGenerateMetadata: result.has_generate_metadata,
61
+ };
62
+ }
63
+ return {
64
+ hasMetadata: /export\s+const\s+metadata\b/.test(source),
65
+ hasGenerateMetadata: /export\s+(async\s+)?function\s+generateMetadata\b/.test(source),
66
+ };
67
+ }
68
+ /**
69
+ * Determine component type from file name
70
+ */
71
+ function getComponentType(fileName) {
72
+ const base = path_1.default.basename(fileName).replace(/\.[jt]sx?$/, '');
73
+ switch (base) {
74
+ case 'page':
75
+ case 'index':
76
+ return 'page';
77
+ case 'layout':
78
+ case 'root':
79
+ return 'layout';
80
+ case 'loading':
81
+ return 'loading';
82
+ case 'error':
83
+ return 'error';
84
+ case 'not-found':
85
+ return 'not-found';
86
+ default:
87
+ return 'component';
88
+ }
89
+ }
90
+ /**
91
+ * Extract client component imports from source
92
+ */
93
+ function extractClientImports(source, appDir) {
94
+ const imports = [];
95
+ // Match import statements
96
+ const importRegex = /import\s+(?:[\w\s{},*]+)\s+from\s+['"]([^'"]+)['"]/g;
97
+ let match;
98
+ while ((match = importRegex.exec(source)) !== null) {
99
+ const importPath = match[1];
100
+ // Skip node_modules
101
+ if (!importPath.startsWith('.') && !importPath.startsWith('/'))
102
+ continue;
103
+ // This is a relative import - we'd need to resolve and check if it's a client component
104
+ // For now, we'll mark it as a potential dependency
105
+ imports.push(importPath);
106
+ }
107
+ return imports;
108
+ }
109
+ /**
110
+ * Generate unique module ID
111
+ */
112
+ function generateModuleId(relativePath) {
113
+ const normalized = relativePath.replace(/\\/g, '/').replace(/\.[jt]sx?$/, '');
114
+ return `server:${normalized}`;
115
+ }
116
+ /**
117
+ * Scan directory recursively for server components
118
+ */
119
+ function scanForServerComponents(dir, appDir, components) {
120
+ if (!fs_1.default.existsSync(dir))
121
+ return;
122
+ const items = fs_1.default.readdirSync(dir, { withFileTypes: true });
123
+ for (const item of items) {
124
+ const fullPath = path_1.default.join(dir, item.name);
125
+ if (item.isDirectory()) {
126
+ if (!item.name.startsWith('.') && item.name !== 'node_modules' && item.name !== 'api') {
127
+ scanForServerComponents(fullPath, appDir, components);
128
+ }
129
+ }
130
+ else if (item.isFile()) {
131
+ const ext = path_1.default.extname(item.name);
132
+ if (!['.tsx', '.ts', '.jsx', '.js'].includes(ext))
133
+ continue;
134
+ try {
135
+ const source = fs_1.default.readFileSync(fullPath, 'utf-8');
136
+ // Only add if NOT a client component
137
+ if (!hasClientDirective(source)) {
138
+ const relativePath = path_1.default.relative(appDir, fullPath);
139
+ const moduleId = generateModuleId(relativePath);
140
+ const metadata = analyzeMetadata(source);
141
+ components.push({
142
+ id: moduleId,
143
+ path: relativePath,
144
+ absolutePath: fullPath,
145
+ type: getComponentType(item.name),
146
+ hasMetadata: metadata.hasMetadata,
147
+ hasGenerateMetadata: metadata.hasGenerateMetadata,
148
+ clientDependencies: extractClientImports(source, appDir),
149
+ });
150
+ }
151
+ }
152
+ catch (e) {
153
+ console.warn(`[Vista RSC] Failed to read ${fullPath}:`, e);
154
+ }
155
+ }
156
+ }
157
+ }
158
+ /**
159
+ * Build route entries from discovered components
160
+ */
161
+ function buildRoutes(components, appDir) {
162
+ const routes = [];
163
+ const pages = components.filter((c) => c.type === 'page');
164
+ const layouts = components.filter((c) => c.type === 'layout');
165
+ const loadings = components.filter((c) => c.type === 'loading');
166
+ const errors = components.filter((c) => c.type === 'error');
167
+ for (const page of pages) {
168
+ const pageDir = path_1.default.dirname(page.absolutePath);
169
+ const relativePath = path_1.default.relative(appDir, pageDir);
170
+ // Build URL pattern
171
+ let pattern = '/' + relativePath.replace(/\\/g, '/');
172
+ let routeType = 'static';
173
+ // Handle dynamic segments
174
+ pattern = pattern
175
+ .replace(/\[\.\.\.([^\]]+)\]/g, (_, name) => {
176
+ routeType = 'catch-all';
177
+ return `:${name}*`;
178
+ })
179
+ .replace(/\[([^\]]+)\]/g, (_, name) => {
180
+ if (routeType !== 'catch-all')
181
+ routeType = 'dynamic';
182
+ return `:${name}`;
183
+ });
184
+ // Handle route groups - remove (groupname) from URL
185
+ pattern = pattern.replace(/\/\([^)]+\)/g, '');
186
+ // Root page
187
+ if (pattern === '/' || pattern === '') {
188
+ pattern = '/';
189
+ }
190
+ // Find layouts in ancestor directories
191
+ const layoutPaths = [];
192
+ let currentDir = pageDir;
193
+ while (currentDir.startsWith(appDir)) {
194
+ const layout = layouts.find((l) => path_1.default.dirname(l.absolutePath) === currentDir);
195
+ if (layout) {
196
+ layoutPaths.unshift(layout.absolutePath);
197
+ }
198
+ const parent = path_1.default.dirname(currentDir);
199
+ if (parent === currentDir)
200
+ break;
201
+ currentDir = parent;
202
+ }
203
+ // Find loading and error in same directory
204
+ const loading = loadings.find((l) => path_1.default.dirname(l.absolutePath) === pageDir);
205
+ const error = errors.find((e) => path_1.default.dirname(e.absolutePath) === pageDir);
206
+ routes.push({
207
+ pattern,
208
+ pagePath: page.absolutePath,
209
+ layoutPaths,
210
+ loadingPath: loading?.absolutePath,
211
+ errorPath: error?.absolutePath,
212
+ type: routeType,
213
+ });
214
+ }
215
+ // Sort routes: static first, then dynamic, then catch-all
216
+ routes.sort((a, b) => {
217
+ const order = { static: 0, dynamic: 1, 'catch-all': 2 };
218
+ return order[a.type] - order[b.type];
219
+ });
220
+ return routes;
221
+ }
222
+ /**
223
+ * Generate the server component manifest
224
+ */
225
+ function generateServerManifest(cwd, appDir) {
226
+ const components = [];
227
+ scanForServerComponents(appDir, appDir, components);
228
+ const serverModules = {};
229
+ const pathToId = {};
230
+ for (const component of components) {
231
+ serverModules[component.id] = component;
232
+ pathToId[component.path] = component.id;
233
+ pathToId[component.absolutePath] = component.id;
234
+ }
235
+ const routes = buildRoutes(components, appDir);
236
+ // Get or generate build ID
237
+ const buildIdPath = path_1.default.join(cwd, '.vista', 'BUILD_ID');
238
+ let buildId = 'dev';
239
+ try {
240
+ if (fs_1.default.existsSync(buildIdPath)) {
241
+ buildId = fs_1.default.readFileSync(buildIdPath, 'utf-8').trim();
242
+ }
243
+ }
244
+ catch (e) {
245
+ // Use dev
246
+ }
247
+ return {
248
+ buildId,
249
+ serverModules,
250
+ pathToId,
251
+ routes,
252
+ };
253
+ }
254
+ /**
255
+ * Get server component by path
256
+ */
257
+ function getServerComponent(manifest, filePath) {
258
+ const moduleId = manifest.pathToId[filePath];
259
+ if (!moduleId)
260
+ return undefined;
261
+ return manifest.serverModules[moduleId];
262
+ }
263
+ /**
264
+ * Check if a path is a server component
265
+ */
266
+ function isServerComponentPath(manifest, filePath) {
267
+ return filePath in manifest.pathToId;
268
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Vista Flight Loader
3
+ *
4
+ * Rust-powered webpack loader that detects 'client load' directive
5
+ * and marks modules with RSC info for proper bundle separation.
6
+ *
7
+ * This is similar to Next.js's flight-loader but uses Vista's Rust scanner.
8
+ */
9
+ import type { LoaderContext } from 'webpack';
10
+ /**
11
+ * Vista Flight Loader
12
+ *
13
+ * Marks modules with RSC info based on 'client load' directive.
14
+ * Uses Rust for detection when available, falls back to TypeScript.
15
+ */
16
+ export default function vistaFlightLoader(this: LoaderContext<{}>, source: string): string;
17
+ export declare const raw = false;
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ /**
3
+ * Vista Flight Loader
4
+ *
5
+ * Rust-powered webpack loader that detects 'client load' directive
6
+ * and marks modules with RSC info for proper bundle separation.
7
+ *
8
+ * This is similar to Next.js's flight-loader but uses Vista's Rust scanner.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.raw = void 0;
12
+ exports.default = vistaFlightLoader;
13
+ // Try to load Rust native bindings
14
+ let nativeBindings = null;
15
+ try {
16
+ nativeBindings = require('../../../../crates/vista-napi');
17
+ }
18
+ catch (e) {
19
+ // Fall back to TypeScript implementation
20
+ }
21
+ /**
22
+ * Fallback TypeScript implementation of client directive detection
23
+ */
24
+ function hasClientDirective(source) {
25
+ const lines = source.split('\n');
26
+ for (const line of lines) {
27
+ const trimmed = line.trim();
28
+ // Skip empty lines and comments
29
+ if (!trimmed || trimmed.startsWith('//') || trimmed.startsWith('/*')) {
30
+ continue;
31
+ }
32
+ // Check for 'client load' directive
33
+ if (trimmed === "'client load';" || trimmed === '"client load";' ||
34
+ trimmed === "'client load'" || trimmed === '"client load"') {
35
+ return true;
36
+ }
37
+ // If we hit an import or other statement first, it's not a client component
38
+ if (trimmed.startsWith('import') || trimmed.startsWith('export') ||
39
+ trimmed.startsWith('const') || trimmed.startsWith('function')) {
40
+ return false;
41
+ }
42
+ }
43
+ return false;
44
+ }
45
+ /**
46
+ * Vista Flight Loader
47
+ *
48
+ * Marks modules with RSC info based on 'client load' directive.
49
+ * Uses Rust for detection when available, falls back to TypeScript.
50
+ */
51
+ function vistaFlightLoader(source) {
52
+ // Get module's build info
53
+ const buildInfo = this._module.buildInfo;
54
+ const fileName = this.resourcePath.split(/[\\/]/).pop() || '';
55
+ // Only process app directory files
56
+ if (!this.resourcePath.includes('app')) {
57
+ return source;
58
+ }
59
+ if (!buildInfo.rsc) {
60
+ // Detect directive using Rust or fallback
61
+ let isClient = false;
62
+ let directiveLine = 0;
63
+ if (nativeBindings) {
64
+ try {
65
+ const result = nativeBindings.analyzeClientDirective(source);
66
+ isClient = result.isClient;
67
+ directiveLine = result.directiveLine;
68
+ }
69
+ catch (e) {
70
+ // Fallback if Rust call fails
71
+ isClient = hasClientDirective(source);
72
+ }
73
+ }
74
+ else {
75
+ isClient = hasClientDirective(source);
76
+ }
77
+ // Mark module with RSC info (like Next.js does)
78
+ buildInfo.rsc = {
79
+ isClientRef: isClient,
80
+ type: isClient ? 'client' : 'server',
81
+ directiveLine
82
+ };
83
+ // Debug logging (only when VISTA_DEBUG is set)
84
+ if (process.env.VISTA_DEBUG && isClient) {
85
+ console.log(`[Vista Flight Loader] ${fileName}: isClient=${isClient}`);
86
+ }
87
+ }
88
+ // Pass through source unchanged
89
+ // The loader's job is just to mark modules, not transform code
90
+ return source;
91
+ }
92
+ // Allow async loading
93
+ exports.raw = false;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Vista Flight Client Entry Plugin
3
+ *
4
+ * Webpack plugin that creates separate client entries for components
5
+ * marked with 'client load' directive. Uses Rust scanner for detection.
6
+ *
7
+ * This is similar to Next.js's FlightClientEntryPlugin.
8
+ */
9
+ import webpack from 'webpack';
10
+ interface PluginOptions {
11
+ appDir: string;
12
+ dev: boolean;
13
+ }
14
+ interface ClientModuleInfo {
15
+ moduleId: string | number;
16
+ absolutePath: string;
17
+ relativePath: string;
18
+ exports: string[];
19
+ }
20
+ export declare class VistaFlightPlugin {
21
+ private appDir;
22
+ private dev;
23
+ constructor(options: PluginOptions);
24
+ apply(compiler: webpack.Compiler): void;
25
+ /**
26
+ * Collect information about all modules and their RSC status
27
+ */
28
+ private collectModuleInfo;
29
+ /**
30
+ * Generate client reference manifest for hydration
31
+ */
32
+ private generateClientManifest;
33
+ }
34
+ export declare function getClientModules(): Map<string, ClientModuleInfo>;
35
+ export declare function isClientModule(resourcePath: string): boolean;
36
+ export default VistaFlightPlugin;