@vistagenic/vista 0.3.2 → 0.3.4
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/bin/vista.js +79 -109
- package/dist/ai/embeddings.d.ts +11 -11
- package/dist/ai/embeddings.js +71 -71
- package/dist/ai/index.d.ts +10 -10
- package/dist/ai/index.js +26 -26
- package/dist/ai/providers/base.js +85 -85
- package/dist/ai/react/react-server.d.ts +1 -1
- package/dist/ai/react/react-server.js +17 -17
- package/dist/ai/react/use-agent.js +138 -138
- package/dist/auth/core.d.ts +140 -140
- package/dist/auth/core.js +165 -165
- package/dist/auth/index.d.ts +20 -20
- package/dist/auth/index.js +369 -369
- package/dist/auth/react-server.d.ts +1 -1
- package/dist/auth/react-server.js +10 -10
- package/dist/auth/react.d.ts +18 -18
- package/dist/auth/react.js +71 -71
- package/dist/bin/build-rsc-flashpack.js +6 -0
- package/dist/bin/build-rsc.js +555 -492
- package/dist/bin/build.js +365 -353
- package/dist/bin/generate.js +513 -510
- package/dist/bin/webpack.config.d.ts +3 -1
- package/dist/bin/webpack.config.js +7 -4
- package/dist/build/manifest.d.ts +169 -169
- package/dist/build/manifest.js +423 -423
- package/dist/build/rsc/client-manifest.d.ts +62 -62
- package/dist/build/rsc/client-manifest.js +295 -295
- package/dist/build/rsc/compiler.d.ts +3 -1
- package/dist/build/rsc/compiler.js +12 -7
- package/dist/build/rsc/native-scanner.d.ts +135 -135
- package/dist/build/rsc/native-scanner.js +203 -203
- package/dist/build/rsc/react-client-reference-manifest.d.ts +35 -28
- package/dist/build/rsc/react-client-reference-manifest.js +366 -240
- package/dist/build/standalone.js +260 -254
- package/dist/client/dynamic.react-server.d.ts +2 -2
- package/dist/client/dynamic.react-server.js +23 -23
- package/dist/client/link.js +1 -1
- package/dist/client/link.react-server.d.ts +2 -2
- package/dist/client/link.react-server.js +11 -11
- package/dist/client/navigation.js +2 -2
- package/dist/client/navigation.react-server.d.ts +1 -1
- package/dist/client/navigation.react-server.js +17 -17
- package/dist/client/router.react-server.d.ts +1 -1
- package/dist/client/router.react-server.js +17 -17
- package/dist/client/rsc-router.d.ts +1 -3
- package/dist/client/rsc-router.js +98 -45
- package/dist/client/rsc-router.react-server.d.ts +1 -1
- package/dist/client/rsc-router.react-server.js +17 -17
- package/dist/client/script.react-server.d.ts +2 -2
- package/dist/client/script.react-server.js +23 -23
- package/dist/config.d.ts +1 -1
- package/dist/config.js +1 -7
- package/dist/deploy/adapters/cloudflare.js +42 -41
- package/dist/deploy/adapters/docker.d.ts +1 -0
- package/dist/deploy/adapters/docker.js +5 -4
- package/dist/deploy/adapters/netlify.js +60 -27
- package/dist/deploy/adapters/vercel.js +80 -50
- package/dist/deploy/preflight.js +4 -3
- package/dist/deploy/runtime-pack.d.ts +11 -0
- package/dist/deploy/runtime-pack.js +300 -0
- package/dist/deploy/utils.d.ts +7 -1
- package/dist/deploy/utils.js +95 -3
- package/dist/flashpack/command.js +1 -0
- package/dist/flashpack/runtime.js +2 -1
- package/dist/image/get-img-props.js +21 -11
- package/dist/image/image-config.d.ts +2 -0
- package/dist/image/image-config.js +17 -0
- package/dist/image/index.d.ts +18 -3
- package/dist/image/index.js +1 -1
- package/dist/image/react-server.d.ts +1 -2
- package/dist/image/react-server.js +1 -1
- package/dist/index.d.ts +23 -23
- package/dist/index.js +61 -61
- package/dist/server/app-dir.d.ts +22 -0
- package/dist/server/app-dir.js +77 -0
- package/dist/server/app-router-runtime.d.ts +1 -0
- package/dist/server/app-router-runtime.js +34 -9
- package/dist/server/cookie-parse.d.ts +4 -4
- package/dist/server/cookie-parse.js +14 -14
- package/dist/server/engine.js +5 -5
- package/dist/server/hydration-chunks.d.ts +7 -0
- package/dist/server/hydration-chunks.js +49 -0
- package/dist/server/image-optimizer.js +2 -1
- package/dist/server/index.d.ts +109 -109
- package/dist/server/index.js +315 -315
- package/dist/server/middleware-runner.d.ts +125 -125
- package/dist/server/middleware-runner.js +607 -615
- package/dist/server/middleware-security.d.ts +36 -36
- package/dist/server/middleware-security.js +183 -183
- package/dist/server/module-compile-hook.js +706 -695
- package/dist/server/root-resolver.js +6 -5
- package/dist/server/rsc-engine-flashpack.d.ts +3 -1
- package/dist/server/rsc-engine-flashpack.js +12 -1
- package/dist/server/rsc-engine.d.ts +6 -1
- package/dist/server/rsc-engine.js +217 -280
- package/dist/server/rsc-upstream.js +900 -892
- package/dist/server/ssr-webpack-shim.d.ts +6 -0
- package/dist/server/ssr-webpack-shim.js +29 -0
- package/dist/server/static-generator.d.ts +2 -0
- package/dist/server/static-generator.js +33 -32
- package/dist/server/structure-validator.js +2 -1
- package/dist/server/structure-watch.js +2 -0
- package/dist/server/typed-api-runtime.js +639 -635
- package/dist/server/vista-import-map.js +134 -134
- package/dist/stack/index.d.ts +34 -34
- package/dist/stack/index.js +49 -49
- package/dist/stack/server/caller.d.ts +13 -13
- package/dist/stack/server/caller.js +42 -42
- package/dist/stack/server/executor.d.ts +40 -40
- package/dist/stack/server/executor.js +222 -222
- package/dist/stack/server/index.d.ts +11 -11
- package/dist/stack/server/index.js +24 -24
- package/dist/stack/server/procedure.d.ts +20 -20
- package/dist/stack/server/procedure.js +66 -66
- package/dist/stack/server/types.d.ts +113 -113
- package/dist/theme/react-server.d.ts +10 -10
- package/dist/theme/react-server.js +16 -16
- package/package.json +1 -1
|
@@ -1,295 +1,295 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Client Component Manifest Generator
|
|
4
|
-
*
|
|
5
|
-
* Scans the app directory and builds a manifest of all Client Components.
|
|
6
|
-
* Client components are those with 'use client' directive.
|
|
7
|
-
*
|
|
8
|
-
* The manifest maps component paths to their chunk names for client-side loading.
|
|
9
|
-
*/
|
|
10
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
11
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
12
|
-
};
|
|
13
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.discoverProjectClientRoots = discoverProjectClientRoots;
|
|
15
|
-
exports.generateClientManifest = generateClientManifest;
|
|
16
|
-
exports.generateClientManifestWithRoots = generateClientManifestWithRoots;
|
|
17
|
-
exports.getClientComponent = getClientComponent;
|
|
18
|
-
exports.getClientComponentByPath = getClientComponentByPath;
|
|
19
|
-
exports.isClientComponentPath = isClientComponentPath;
|
|
20
|
-
const fs_1 = __importDefault(require("fs"));
|
|
21
|
-
const path_1 = __importDefault(require("path"));
|
|
22
|
-
const component_identity_1 = require("./component-identity");
|
|
23
|
-
const constants_1 = require("../../constants");
|
|
24
|
-
const native_scanner_1 = require("./native-scanner");
|
|
25
|
-
const PROJECT_CLIENT_SCAN_SKIP = new Set([
|
|
26
|
-
'node_modules',
|
|
27
|
-
'.vista',
|
|
28
|
-
'.flash',
|
|
29
|
-
'dist',
|
|
30
|
-
'public',
|
|
31
|
-
'coverage',
|
|
32
|
-
'build',
|
|
33
|
-
'out',
|
|
34
|
-
]);
|
|
35
|
-
/**
|
|
36
|
-
* Top-level app directories that may contain `'use client'` modules.
|
|
37
|
-
* Discovery is directory membership, not the import graph, so `utils/`,
|
|
38
|
-
* `lib/`, and `src/` have to be scanned explicitly or they never enter
|
|
39
|
-
* the React Client Manifest.
|
|
40
|
-
*/
|
|
41
|
-
function discoverProjectClientRoots(cwd) {
|
|
42
|
-
const roots = [];
|
|
43
|
-
if (!fs_1.default.existsSync(cwd)) {
|
|
44
|
-
return roots;
|
|
45
|
-
}
|
|
46
|
-
let entries;
|
|
47
|
-
try {
|
|
48
|
-
entries = fs_1.default.readdirSync(cwd, { withFileTypes: true });
|
|
49
|
-
}
|
|
50
|
-
catch {
|
|
51
|
-
return roots;
|
|
52
|
-
}
|
|
53
|
-
for (const entry of entries) {
|
|
54
|
-
if (!entry.isDirectory())
|
|
55
|
-
continue;
|
|
56
|
-
if (entry.name.startsWith('.'))
|
|
57
|
-
continue;
|
|
58
|
-
if (PROJECT_CLIENT_SCAN_SKIP.has(entry.name))
|
|
59
|
-
continue;
|
|
60
|
-
roots.push({
|
|
61
|
-
dir: path_1.default.join(cwd, entry.name),
|
|
62
|
-
prefix: `${entry.name.replace(/\\/g, '/')}/`,
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
return roots;
|
|
66
|
-
}
|
|
67
|
-
// Try to load Rust NAPI bindings
|
|
68
|
-
let rustNative = null;
|
|
69
|
-
try {
|
|
70
|
-
const possiblePaths = [
|
|
71
|
-
path_1.default.resolve(__dirname, '../../../../../crates/vista-napi'),
|
|
72
|
-
path_1.default.resolve(__dirname, '../../../../crates/vista-napi'),
|
|
73
|
-
];
|
|
74
|
-
for (const p of possiblePaths) {
|
|
75
|
-
try {
|
|
76
|
-
rustNative = require(p);
|
|
77
|
-
break;
|
|
78
|
-
}
|
|
79
|
-
catch (e) {
|
|
80
|
-
// Try next
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
catch (e) {
|
|
85
|
-
// Fallback to JS
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Check if source has 'use client' directive
|
|
89
|
-
*/
|
|
90
|
-
function hasClientDirective(source) {
|
|
91
|
-
const trimmed = source.trimStart();
|
|
92
|
-
if (trimmed.startsWith("'use client'") || trimmed.startsWith('"use client"')) {
|
|
93
|
-
return true;
|
|
94
|
-
}
|
|
95
|
-
if (rustNative?.isClientComponent) {
|
|
96
|
-
return rustNative.isClientComponent(source);
|
|
97
|
-
}
|
|
98
|
-
return false;
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* Extract export names from source (simple regex approach)
|
|
102
|
-
*/
|
|
103
|
-
function extractExports(source) {
|
|
104
|
-
const exports = [];
|
|
105
|
-
// Default export
|
|
106
|
-
if (/export\s+default\s+/.test(source)) {
|
|
107
|
-
exports.push('default');
|
|
108
|
-
}
|
|
109
|
-
// Named exports: export function Name, export const Name, export class Name
|
|
110
|
-
const namedExportRegex = /export\s+(?:async\s+)?(?:function|const|let|var|class)\s+([A-Z][a-zA-Z0-9_]*)/g;
|
|
111
|
-
let match;
|
|
112
|
-
while ((match = namedExportRegex.exec(source)) !== null) {
|
|
113
|
-
exports.push(match[1]);
|
|
114
|
-
}
|
|
115
|
-
// Export { Name1, Name2 }
|
|
116
|
-
const reExportRegex = /export\s+\{([^}]+)\}/g;
|
|
117
|
-
while ((match = reExportRegex.exec(source)) !== null) {
|
|
118
|
-
const names = match[1]
|
|
119
|
-
.split(',')
|
|
120
|
-
.map((n) => n
|
|
121
|
-
.trim()
|
|
122
|
-
.split(/\s+as\s+/)
|
|
123
|
-
.pop()
|
|
124
|
-
?.trim())
|
|
125
|
-
.filter(Boolean);
|
|
126
|
-
exports.push(...names);
|
|
127
|
-
}
|
|
128
|
-
return [...new Set(exports)];
|
|
129
|
-
}
|
|
130
|
-
function isSameOrInside(target, ancestor) {
|
|
131
|
-
const resolvedTarget = path_1.default.resolve(target);
|
|
132
|
-
const resolvedAncestor = path_1.default.resolve(ancestor);
|
|
133
|
-
if (resolvedTarget === resolvedAncestor)
|
|
134
|
-
return true;
|
|
135
|
-
const prefix = resolvedAncestor.endsWith(path_1.default.sep)
|
|
136
|
-
? resolvedAncestor
|
|
137
|
-
: `${resolvedAncestor}${path_1.default.sep}`;
|
|
138
|
-
return resolvedTarget.startsWith(prefix);
|
|
139
|
-
}
|
|
140
|
-
function additionalRootsMatchDiscovery(cwd, appDir, additionalRoots) {
|
|
141
|
-
const discovered = discoverProjectClientRoots(cwd).filter((root) => path_1.default.resolve(root.dir) !== path_1.default.resolve(appDir));
|
|
142
|
-
if (additionalRoots.length !== discovered.length)
|
|
143
|
-
return false;
|
|
144
|
-
const extra = new Set(additionalRoots.map((root) => path_1.default.resolve(root.dir)));
|
|
145
|
-
return discovered.every((root) => extra.has(path_1.default.resolve(root.dir)));
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Scan directory recursively for client components
|
|
149
|
-
*/
|
|
150
|
-
function scanForClientComponents(dir, scanRoot, components, pathPrefix = '', skipInside) {
|
|
151
|
-
if (!fs_1.default.existsSync(dir))
|
|
152
|
-
return;
|
|
153
|
-
if (skipInside && isSameOrInside(dir, skipInside))
|
|
154
|
-
return;
|
|
155
|
-
const items = fs_1.default.readdirSync(dir, { withFileTypes: true });
|
|
156
|
-
for (const item of items) {
|
|
157
|
-
const fullPath = path_1.default.join(dir, item.name);
|
|
158
|
-
if (item.isDirectory()) {
|
|
159
|
-
if (!item.name.startsWith('.') && item.name !== 'node_modules') {
|
|
160
|
-
scanForClientComponents(fullPath, scanRoot, components, pathPrefix, skipInside);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
else if (item.isFile()) {
|
|
164
|
-
if (skipInside && isSameOrInside(fullPath, skipInside))
|
|
165
|
-
continue;
|
|
166
|
-
const ext = path_1.default.extname(item.name);
|
|
167
|
-
if (!['.tsx', '.ts', '.jsx', '.js'].includes(ext))
|
|
168
|
-
continue;
|
|
169
|
-
try {
|
|
170
|
-
const source = fs_1.default.readFileSync(fullPath, 'utf-8');
|
|
171
|
-
if (hasClientDirective(source)) {
|
|
172
|
-
const relativePathBase = (0, component_identity_1.relativeComponentPath)(scanRoot, fullPath);
|
|
173
|
-
const relativePath = pathPrefix ? `${pathPrefix}${relativePathBase}` : relativePathBase;
|
|
174
|
-
const moduleId = (0, component_identity_1.createComponentId)('client', relativePath);
|
|
175
|
-
components.push({
|
|
176
|
-
id: moduleId,
|
|
177
|
-
path: relativePath,
|
|
178
|
-
absolutePath: fullPath,
|
|
179
|
-
chunkName: (0, component_identity_1.createChunkName)(relativePath),
|
|
180
|
-
exports: extractExports(source),
|
|
181
|
-
async: false,
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
catch (e) {
|
|
186
|
-
console.warn(`[Vista RSC] Failed to read ${fullPath}:`, e);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* Generate the client component manifest
|
|
193
|
-
*/
|
|
194
|
-
function generateClientManifest(cwd, appDir) {
|
|
195
|
-
const additionalRoots = discoverProjectClientRoots(cwd).filter((root) => path_1.default.resolve(root.dir) !== path_1.default.resolve(appDir));
|
|
196
|
-
return generateClientManifestWithRoots(cwd, appDir, additionalRoots);
|
|
197
|
-
}
|
|
198
|
-
function readBuildId(cwd) {
|
|
199
|
-
const buildIdPath = path_1.default.join(cwd, constants_1.BUILD_DIR, 'BUILD_ID');
|
|
200
|
-
try {
|
|
201
|
-
if (fs_1.default.existsSync(buildIdPath)) {
|
|
202
|
-
return fs_1.default.readFileSync(buildIdPath, 'utf-8').trim();
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
catch {
|
|
206
|
-
// Use dev
|
|
207
|
-
}
|
|
208
|
-
return 'dev';
|
|
209
|
-
}
|
|
210
|
-
function nativeClientManifestToJs(native) {
|
|
211
|
-
const clientModules = {};
|
|
212
|
-
const pathToId = {};
|
|
213
|
-
const ssrModuleMapping = {};
|
|
214
|
-
for (const component of native.clientModules) {
|
|
215
|
-
const entry = {
|
|
216
|
-
id: component.id,
|
|
217
|
-
path: component.path,
|
|
218
|
-
absolutePath: component.absolutePath,
|
|
219
|
-
chunkName: component.chunkName,
|
|
220
|
-
exports: component.exports,
|
|
221
|
-
async: component.asyncLoad,
|
|
222
|
-
};
|
|
223
|
-
clientModules[component.id] = entry;
|
|
224
|
-
const normalizedRelativePath = (0, component_identity_1.normalizeComponentPath)(component.path);
|
|
225
|
-
const normalizedAbsolutePath = (0, component_identity_1.normalizeComponentPath)(component.absolutePath);
|
|
226
|
-
pathToId[component.path] = component.id;
|
|
227
|
-
pathToId[normalizedRelativePath] = component.id;
|
|
228
|
-
pathToId[component.absolutePath] = component.id;
|
|
229
|
-
pathToId[normalizedAbsolutePath] = component.id;
|
|
230
|
-
ssrModuleMapping[component.absolutePath] = `${constants_1.STATIC_CHUNKS_PATH}${component.chunkName}.js`;
|
|
231
|
-
ssrModuleMapping[normalizedAbsolutePath] = `${constants_1.STATIC_CHUNKS_PATH}${component.chunkName}.js`;
|
|
232
|
-
}
|
|
233
|
-
return {
|
|
234
|
-
buildId: native.buildId,
|
|
235
|
-
clientModules,
|
|
236
|
-
pathToId,
|
|
237
|
-
ssrModuleMapping,
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
function generateClientManifestWithRoots(cwd, appDir, additionalRoots = []) {
|
|
241
|
-
if (additionalRootsMatchDiscovery(cwd, appDir, additionalRoots)) {
|
|
242
|
-
const native = (0, native_scanner_1.generateClientManifestForProjectNative)(cwd, appDir, readBuildId(cwd));
|
|
243
|
-
if (native && Array.isArray(native.clientModules)) {
|
|
244
|
-
return nativeClientManifestToJs(native);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
const components = [];
|
|
248
|
-
scanForClientComponents(appDir, appDir, components);
|
|
249
|
-
for (const root of additionalRoots) {
|
|
250
|
-
if (!fs_1.default.existsSync(root.dir))
|
|
251
|
-
continue;
|
|
252
|
-
scanForClientComponents(root.dir, root.dir, components, root.prefix || '', appDir);
|
|
253
|
-
}
|
|
254
|
-
const clientModules = {};
|
|
255
|
-
const pathToId = {};
|
|
256
|
-
const ssrModuleMapping = {};
|
|
257
|
-
for (const component of components) {
|
|
258
|
-
clientModules[component.id] = component;
|
|
259
|
-
const normalizedRelativePath = (0, component_identity_1.normalizeComponentPath)(component.path);
|
|
260
|
-
const normalizedAbsolutePath = (0, component_identity_1.normalizeComponentPath)(component.absolutePath);
|
|
261
|
-
pathToId[component.path] = component.id;
|
|
262
|
-
pathToId[normalizedRelativePath] = component.id;
|
|
263
|
-
pathToId[component.absolutePath] = component.id;
|
|
264
|
-
pathToId[normalizedAbsolutePath] = component.id;
|
|
265
|
-
ssrModuleMapping[component.absolutePath] = `${constants_1.STATIC_CHUNKS_PATH}${component.chunkName}.js`;
|
|
266
|
-
ssrModuleMapping[normalizedAbsolutePath] = `${constants_1.STATIC_CHUNKS_PATH}${component.chunkName}.js`;
|
|
267
|
-
}
|
|
268
|
-
return {
|
|
269
|
-
buildId: readBuildId(cwd),
|
|
270
|
-
clientModules,
|
|
271
|
-
pathToId,
|
|
272
|
-
ssrModuleMapping,
|
|
273
|
-
};
|
|
274
|
-
}
|
|
275
|
-
/**
|
|
276
|
-
* Get client component info by module ID
|
|
277
|
-
*/
|
|
278
|
-
function getClientComponent(manifest, moduleId) {
|
|
279
|
-
return manifest.clientModules[moduleId];
|
|
280
|
-
}
|
|
281
|
-
/**
|
|
282
|
-
* Get client component by file path
|
|
283
|
-
*/
|
|
284
|
-
function getClientComponentByPath(manifest, filePath) {
|
|
285
|
-
const moduleId = manifest.pathToId[filePath];
|
|
286
|
-
if (!moduleId)
|
|
287
|
-
return undefined;
|
|
288
|
-
return manifest.clientModules[moduleId];
|
|
289
|
-
}
|
|
290
|
-
/**
|
|
291
|
-
* Check if a path is a client component
|
|
292
|
-
*/
|
|
293
|
-
function isClientComponentPath(manifest, filePath) {
|
|
294
|
-
return filePath in manifest.pathToId;
|
|
295
|
-
}
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Client Component Manifest Generator
|
|
4
|
+
*
|
|
5
|
+
* Scans the app directory and builds a manifest of all Client Components.
|
|
6
|
+
* Client components are those with 'use client' directive.
|
|
7
|
+
*
|
|
8
|
+
* The manifest maps component paths to their chunk names for client-side loading.
|
|
9
|
+
*/
|
|
10
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
11
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
12
|
+
};
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.discoverProjectClientRoots = discoverProjectClientRoots;
|
|
15
|
+
exports.generateClientManifest = generateClientManifest;
|
|
16
|
+
exports.generateClientManifestWithRoots = generateClientManifestWithRoots;
|
|
17
|
+
exports.getClientComponent = getClientComponent;
|
|
18
|
+
exports.getClientComponentByPath = getClientComponentByPath;
|
|
19
|
+
exports.isClientComponentPath = isClientComponentPath;
|
|
20
|
+
const fs_1 = __importDefault(require("fs"));
|
|
21
|
+
const path_1 = __importDefault(require("path"));
|
|
22
|
+
const component_identity_1 = require("./component-identity");
|
|
23
|
+
const constants_1 = require("../../constants");
|
|
24
|
+
const native_scanner_1 = require("./native-scanner");
|
|
25
|
+
const PROJECT_CLIENT_SCAN_SKIP = new Set([
|
|
26
|
+
'node_modules',
|
|
27
|
+
'.vista',
|
|
28
|
+
'.flash',
|
|
29
|
+
'dist',
|
|
30
|
+
'public',
|
|
31
|
+
'coverage',
|
|
32
|
+
'build',
|
|
33
|
+
'out',
|
|
34
|
+
]);
|
|
35
|
+
/**
|
|
36
|
+
* Top-level app directories that may contain `'use client'` modules.
|
|
37
|
+
* Discovery is directory membership, not the import graph, so `utils/`,
|
|
38
|
+
* `lib/`, and `src/` have to be scanned explicitly or they never enter
|
|
39
|
+
* the React Client Manifest.
|
|
40
|
+
*/
|
|
41
|
+
function discoverProjectClientRoots(cwd) {
|
|
42
|
+
const roots = [];
|
|
43
|
+
if (!fs_1.default.existsSync(cwd)) {
|
|
44
|
+
return roots;
|
|
45
|
+
}
|
|
46
|
+
let entries;
|
|
47
|
+
try {
|
|
48
|
+
entries = fs_1.default.readdirSync(cwd, { withFileTypes: true });
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return roots;
|
|
52
|
+
}
|
|
53
|
+
for (const entry of entries) {
|
|
54
|
+
if (!entry.isDirectory())
|
|
55
|
+
continue;
|
|
56
|
+
if (entry.name.startsWith('.'))
|
|
57
|
+
continue;
|
|
58
|
+
if (PROJECT_CLIENT_SCAN_SKIP.has(entry.name))
|
|
59
|
+
continue;
|
|
60
|
+
roots.push({
|
|
61
|
+
dir: path_1.default.join(cwd, entry.name),
|
|
62
|
+
prefix: `${entry.name.replace(/\\/g, '/')}/`,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return roots;
|
|
66
|
+
}
|
|
67
|
+
// Try to load Rust NAPI bindings
|
|
68
|
+
let rustNative = null;
|
|
69
|
+
try {
|
|
70
|
+
const possiblePaths = [
|
|
71
|
+
path_1.default.resolve(__dirname, '../../../../../crates/vista-napi'),
|
|
72
|
+
path_1.default.resolve(__dirname, '../../../../crates/vista-napi'),
|
|
73
|
+
];
|
|
74
|
+
for (const p of possiblePaths) {
|
|
75
|
+
try {
|
|
76
|
+
rustNative = require(p);
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
// Try next
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (e) {
|
|
85
|
+
// Fallback to JS
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Check if source has 'use client' directive
|
|
89
|
+
*/
|
|
90
|
+
function hasClientDirective(source) {
|
|
91
|
+
const trimmed = source.trimStart();
|
|
92
|
+
if (trimmed.startsWith("'use client'") || trimmed.startsWith('"use client"')) {
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
if (rustNative?.isClientComponent) {
|
|
96
|
+
return rustNative.isClientComponent(source);
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Extract export names from source (simple regex approach)
|
|
102
|
+
*/
|
|
103
|
+
function extractExports(source) {
|
|
104
|
+
const exports = [];
|
|
105
|
+
// Default export
|
|
106
|
+
if (/export\s+default\s+/.test(source)) {
|
|
107
|
+
exports.push('default');
|
|
108
|
+
}
|
|
109
|
+
// Named exports: export function Name, export const Name, export class Name
|
|
110
|
+
const namedExportRegex = /export\s+(?:async\s+)?(?:function|const|let|var|class)\s+([A-Z][a-zA-Z0-9_]*)/g;
|
|
111
|
+
let match;
|
|
112
|
+
while ((match = namedExportRegex.exec(source)) !== null) {
|
|
113
|
+
exports.push(match[1]);
|
|
114
|
+
}
|
|
115
|
+
// Export { Name1, Name2 }
|
|
116
|
+
const reExportRegex = /export\s+\{([^}]+)\}/g;
|
|
117
|
+
while ((match = reExportRegex.exec(source)) !== null) {
|
|
118
|
+
const names = match[1]
|
|
119
|
+
.split(',')
|
|
120
|
+
.map((n) => n
|
|
121
|
+
.trim()
|
|
122
|
+
.split(/\s+as\s+/)
|
|
123
|
+
.pop()
|
|
124
|
+
?.trim())
|
|
125
|
+
.filter(Boolean);
|
|
126
|
+
exports.push(...names);
|
|
127
|
+
}
|
|
128
|
+
return [...new Set(exports)];
|
|
129
|
+
}
|
|
130
|
+
function isSameOrInside(target, ancestor) {
|
|
131
|
+
const resolvedTarget = path_1.default.resolve(target);
|
|
132
|
+
const resolvedAncestor = path_1.default.resolve(ancestor);
|
|
133
|
+
if (resolvedTarget === resolvedAncestor)
|
|
134
|
+
return true;
|
|
135
|
+
const prefix = resolvedAncestor.endsWith(path_1.default.sep)
|
|
136
|
+
? resolvedAncestor
|
|
137
|
+
: `${resolvedAncestor}${path_1.default.sep}`;
|
|
138
|
+
return resolvedTarget.startsWith(prefix);
|
|
139
|
+
}
|
|
140
|
+
function additionalRootsMatchDiscovery(cwd, appDir, additionalRoots) {
|
|
141
|
+
const discovered = discoverProjectClientRoots(cwd).filter((root) => path_1.default.resolve(root.dir) !== path_1.default.resolve(appDir));
|
|
142
|
+
if (additionalRoots.length !== discovered.length)
|
|
143
|
+
return false;
|
|
144
|
+
const extra = new Set(additionalRoots.map((root) => path_1.default.resolve(root.dir)));
|
|
145
|
+
return discovered.every((root) => extra.has(path_1.default.resolve(root.dir)));
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Scan directory recursively for client components
|
|
149
|
+
*/
|
|
150
|
+
function scanForClientComponents(dir, scanRoot, components, pathPrefix = '', skipInside) {
|
|
151
|
+
if (!fs_1.default.existsSync(dir))
|
|
152
|
+
return;
|
|
153
|
+
if (skipInside && isSameOrInside(dir, skipInside))
|
|
154
|
+
return;
|
|
155
|
+
const items = fs_1.default.readdirSync(dir, { withFileTypes: true });
|
|
156
|
+
for (const item of items) {
|
|
157
|
+
const fullPath = path_1.default.join(dir, item.name);
|
|
158
|
+
if (item.isDirectory()) {
|
|
159
|
+
if (!item.name.startsWith('.') && item.name !== 'node_modules') {
|
|
160
|
+
scanForClientComponents(fullPath, scanRoot, components, pathPrefix, skipInside);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
else if (item.isFile()) {
|
|
164
|
+
if (skipInside && isSameOrInside(fullPath, skipInside))
|
|
165
|
+
continue;
|
|
166
|
+
const ext = path_1.default.extname(item.name);
|
|
167
|
+
if (!['.tsx', '.ts', '.jsx', '.js'].includes(ext))
|
|
168
|
+
continue;
|
|
169
|
+
try {
|
|
170
|
+
const source = fs_1.default.readFileSync(fullPath, 'utf-8');
|
|
171
|
+
if (hasClientDirective(source)) {
|
|
172
|
+
const relativePathBase = (0, component_identity_1.relativeComponentPath)(scanRoot, fullPath);
|
|
173
|
+
const relativePath = pathPrefix ? `${pathPrefix}${relativePathBase}` : relativePathBase;
|
|
174
|
+
const moduleId = (0, component_identity_1.createComponentId)('client', relativePath);
|
|
175
|
+
components.push({
|
|
176
|
+
id: moduleId,
|
|
177
|
+
path: relativePath,
|
|
178
|
+
absolutePath: fullPath,
|
|
179
|
+
chunkName: (0, component_identity_1.createChunkName)(relativePath),
|
|
180
|
+
exports: extractExports(source),
|
|
181
|
+
async: false,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
catch (e) {
|
|
186
|
+
console.warn(`[Vista RSC] Failed to read ${fullPath}:`, e);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Generate the client component manifest
|
|
193
|
+
*/
|
|
194
|
+
function generateClientManifest(cwd, appDir) {
|
|
195
|
+
const additionalRoots = discoverProjectClientRoots(cwd).filter((root) => path_1.default.resolve(root.dir) !== path_1.default.resolve(appDir));
|
|
196
|
+
return generateClientManifestWithRoots(cwd, appDir, additionalRoots);
|
|
197
|
+
}
|
|
198
|
+
function readBuildId(cwd) {
|
|
199
|
+
const buildIdPath = path_1.default.join(cwd, constants_1.BUILD_DIR, 'BUILD_ID');
|
|
200
|
+
try {
|
|
201
|
+
if (fs_1.default.existsSync(buildIdPath)) {
|
|
202
|
+
return fs_1.default.readFileSync(buildIdPath, 'utf-8').trim();
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
// Use dev
|
|
207
|
+
}
|
|
208
|
+
return 'dev';
|
|
209
|
+
}
|
|
210
|
+
function nativeClientManifestToJs(native) {
|
|
211
|
+
const clientModules = {};
|
|
212
|
+
const pathToId = {};
|
|
213
|
+
const ssrModuleMapping = {};
|
|
214
|
+
for (const component of native.clientModules) {
|
|
215
|
+
const entry = {
|
|
216
|
+
id: component.id,
|
|
217
|
+
path: component.path,
|
|
218
|
+
absolutePath: component.absolutePath,
|
|
219
|
+
chunkName: component.chunkName,
|
|
220
|
+
exports: component.exports,
|
|
221
|
+
async: component.asyncLoad,
|
|
222
|
+
};
|
|
223
|
+
clientModules[component.id] = entry;
|
|
224
|
+
const normalizedRelativePath = (0, component_identity_1.normalizeComponentPath)(component.path);
|
|
225
|
+
const normalizedAbsolutePath = (0, component_identity_1.normalizeComponentPath)(component.absolutePath);
|
|
226
|
+
pathToId[component.path] = component.id;
|
|
227
|
+
pathToId[normalizedRelativePath] = component.id;
|
|
228
|
+
pathToId[component.absolutePath] = component.id;
|
|
229
|
+
pathToId[normalizedAbsolutePath] = component.id;
|
|
230
|
+
ssrModuleMapping[component.absolutePath] = `${constants_1.STATIC_CHUNKS_PATH}${component.chunkName}.js`;
|
|
231
|
+
ssrModuleMapping[normalizedAbsolutePath] = `${constants_1.STATIC_CHUNKS_PATH}${component.chunkName}.js`;
|
|
232
|
+
}
|
|
233
|
+
return {
|
|
234
|
+
buildId: native.buildId,
|
|
235
|
+
clientModules,
|
|
236
|
+
pathToId,
|
|
237
|
+
ssrModuleMapping,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
function generateClientManifestWithRoots(cwd, appDir, additionalRoots = []) {
|
|
241
|
+
if (additionalRootsMatchDiscovery(cwd, appDir, additionalRoots)) {
|
|
242
|
+
const native = (0, native_scanner_1.generateClientManifestForProjectNative)(cwd, appDir, readBuildId(cwd));
|
|
243
|
+
if (native && Array.isArray(native.clientModules)) {
|
|
244
|
+
return nativeClientManifestToJs(native);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
const components = [];
|
|
248
|
+
scanForClientComponents(appDir, appDir, components);
|
|
249
|
+
for (const root of additionalRoots) {
|
|
250
|
+
if (!fs_1.default.existsSync(root.dir))
|
|
251
|
+
continue;
|
|
252
|
+
scanForClientComponents(root.dir, root.dir, components, root.prefix || '', appDir);
|
|
253
|
+
}
|
|
254
|
+
const clientModules = {};
|
|
255
|
+
const pathToId = {};
|
|
256
|
+
const ssrModuleMapping = {};
|
|
257
|
+
for (const component of components) {
|
|
258
|
+
clientModules[component.id] = component;
|
|
259
|
+
const normalizedRelativePath = (0, component_identity_1.normalizeComponentPath)(component.path);
|
|
260
|
+
const normalizedAbsolutePath = (0, component_identity_1.normalizeComponentPath)(component.absolutePath);
|
|
261
|
+
pathToId[component.path] = component.id;
|
|
262
|
+
pathToId[normalizedRelativePath] = component.id;
|
|
263
|
+
pathToId[component.absolutePath] = component.id;
|
|
264
|
+
pathToId[normalizedAbsolutePath] = component.id;
|
|
265
|
+
ssrModuleMapping[component.absolutePath] = `${constants_1.STATIC_CHUNKS_PATH}${component.chunkName}.js`;
|
|
266
|
+
ssrModuleMapping[normalizedAbsolutePath] = `${constants_1.STATIC_CHUNKS_PATH}${component.chunkName}.js`;
|
|
267
|
+
}
|
|
268
|
+
return {
|
|
269
|
+
buildId: readBuildId(cwd),
|
|
270
|
+
clientModules,
|
|
271
|
+
pathToId,
|
|
272
|
+
ssrModuleMapping,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Get client component info by module ID
|
|
277
|
+
*/
|
|
278
|
+
function getClientComponent(manifest, moduleId) {
|
|
279
|
+
return manifest.clientModules[moduleId];
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Get client component by file path
|
|
283
|
+
*/
|
|
284
|
+
function getClientComponentByPath(manifest, filePath) {
|
|
285
|
+
const moduleId = manifest.pathToId[filePath];
|
|
286
|
+
if (!moduleId)
|
|
287
|
+
return undefined;
|
|
288
|
+
return manifest.clientModules[moduleId];
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Check if a path is a client component
|
|
292
|
+
*/
|
|
293
|
+
function isClientComponentPath(manifest, filePath) {
|
|
294
|
+
return filePath in manifest.pathToId;
|
|
295
|
+
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import webpack from 'webpack';
|
|
9
9
|
import { VistaDirs } from '../manifest';
|
|
10
|
-
import type { VistaEngineVariant } from '../../config';
|
|
10
|
+
import type { DeployOutput, VistaEngineVariant } from '../../config';
|
|
11
11
|
export interface RSCCompilerOptions {
|
|
12
12
|
cwd: string;
|
|
13
13
|
isDev: boolean;
|
|
@@ -15,6 +15,8 @@ export interface RSCCompilerOptions {
|
|
|
15
15
|
buildId: string;
|
|
16
16
|
engineVariant?: VistaEngineVariant;
|
|
17
17
|
clientReferenceFiles?: string[];
|
|
18
|
+
imagesUnoptimized?: boolean;
|
|
19
|
+
deployOutput?: DeployOutput;
|
|
18
20
|
}
|
|
19
21
|
/**
|
|
20
22
|
* Create Server-Side Webpack Configuration
|