@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.
- package/bin/vista.js +98 -0
- package/dist/auth/index.d.ts +8 -0
- package/dist/auth/index.js +16 -0
- package/dist/bin/build-rsc.d.ts +17 -0
- package/dist/bin/build-rsc.js +320 -0
- package/dist/bin/build.d.ts +4 -0
- package/dist/bin/build.js +336 -0
- package/dist/bin/file-scanner.d.ts +66 -0
- package/dist/bin/file-scanner.js +399 -0
- package/dist/bin/server-component-plugin.d.ts +17 -0
- package/dist/bin/server-component-plugin.js +133 -0
- package/dist/bin/webpack.config.d.ts +6 -0
- package/dist/bin/webpack.config.js +138 -0
- package/dist/build/manifest.d.ts +95 -0
- package/dist/build/manifest.js +168 -0
- package/dist/build/rsc/client-manifest.d.ts +48 -0
- package/dist/build/rsc/client-manifest.js +191 -0
- package/dist/build/rsc/client-reference-plugin.d.ts +37 -0
- package/dist/build/rsc/client-reference-plugin.js +185 -0
- package/dist/build/rsc/compiler.d.ts +36 -0
- package/dist/build/rsc/compiler.js +311 -0
- package/dist/build/rsc/index.d.ts +16 -0
- package/dist/build/rsc/index.js +32 -0
- package/dist/build/rsc/native-scanner.d.ts +123 -0
- package/dist/build/rsc/native-scanner.js +165 -0
- package/dist/build/rsc/rsc-renderer.d.ts +99 -0
- package/dist/build/rsc/rsc-renderer.js +269 -0
- package/dist/build/rsc/server-component-loader.d.ts +19 -0
- package/dist/build/rsc/server-component-loader.js +147 -0
- package/dist/build/rsc/server-manifest.d.ts +63 -0
- package/dist/build/rsc/server-manifest.js +268 -0
- package/dist/build/webpack/loaders/vista-flight-loader.d.ts +17 -0
- package/dist/build/webpack/loaders/vista-flight-loader.js +93 -0
- package/dist/build/webpack/plugins/vista-flight-plugin.d.ts +36 -0
- package/dist/build/webpack/plugins/vista-flight-plugin.js +133 -0
- package/dist/client/dynamic.d.ts +25 -0
- package/dist/client/dynamic.js +68 -0
- package/dist/client/font.d.ts +98 -0
- package/dist/client/font.js +109 -0
- package/dist/client/head.d.ts +79 -0
- package/dist/client/head.js +261 -0
- package/dist/client/hydration.d.ts +45 -0
- package/dist/client/hydration.js +291 -0
- package/dist/client/link.d.ts +30 -0
- package/dist/client/link.js +188 -0
- package/dist/client/navigation.d.ts +28 -0
- package/dist/client/navigation.js +116 -0
- package/dist/client/router.d.ts +41 -0
- package/dist/client/router.js +190 -0
- package/dist/client/script.d.ts +51 -0
- package/dist/client/script.js +118 -0
- package/dist/components/client-island.d.ts +34 -0
- package/dist/components/client-island.js +75 -0
- package/dist/components/client.d.ts +29 -0
- package/dist/components/client.js +102 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +8 -0
- package/dist/components/link.d.ts +6 -0
- package/dist/components/link.js +13 -0
- package/dist/config.d.ts +10 -0
- package/dist/config.js +31 -0
- package/dist/dev-error.d.ts +35 -0
- package/dist/dev-error.js +310 -0
- package/dist/image/get-img-props.d.ts +28 -0
- package/dist/image/get-img-props.js +49 -0
- package/dist/image/image-config.d.ts +20 -0
- package/dist/image/image-config.js +20 -0
- package/dist/image/image-loader.d.ts +7 -0
- package/dist/image/image-loader.js +14 -0
- package/dist/image/index.d.ts +6 -0
- package/dist/image/index.js +110 -0
- package/dist/image.d.ts +10 -0
- package/dist/image.js +7 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +53 -0
- package/dist/metadata/generate.d.ts +22 -0
- package/dist/metadata/generate.js +324 -0
- package/dist/metadata/index.d.ts +7 -0
- package/dist/metadata/index.js +26 -0
- package/dist/metadata/types.d.ts +325 -0
- package/dist/metadata/types.js +15 -0
- package/dist/router/context.d.ts +8 -0
- package/dist/router/context.js +13 -0
- package/dist/router/index.d.ts +2 -0
- package/dist/router/index.js +18 -0
- package/dist/router/provider.d.ts +5 -0
- package/dist/router/provider.js +31 -0
- package/dist/server/client-boundary.d.ts +48 -0
- package/dist/server/client-boundary.js +133 -0
- package/dist/server/engine.d.ts +4 -0
- package/dist/server/engine.js +651 -0
- package/dist/server/index.d.ts +95 -0
- package/dist/server/index.js +177 -0
- package/dist/server/rsc-engine.d.ts +20 -0
- package/dist/server/rsc-engine.js +588 -0
- package/dist/server/rsc-module-system.d.ts +33 -0
- package/dist/server/rsc-module-system.js +119 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.js +2 -0
- package/package.json +103 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vista Build Utilities
|
|
3
|
+
*
|
|
4
|
+
* Generates build manifests, BUILD_ID, and manages .vista output structure.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Generate a unique build ID based on timestamp and random bytes.
|
|
8
|
+
*/
|
|
9
|
+
export declare function generateBuildId(): string;
|
|
10
|
+
/**
|
|
11
|
+
* Read existing BUILD_ID or generate a new one.
|
|
12
|
+
*/
|
|
13
|
+
export declare function getBuildId(vistaDir: string, forceNew?: boolean): string;
|
|
14
|
+
export interface VistaDirs {
|
|
15
|
+
root: string;
|
|
16
|
+
cache: string;
|
|
17
|
+
server: string;
|
|
18
|
+
static: string;
|
|
19
|
+
chunks: string;
|
|
20
|
+
css: string;
|
|
21
|
+
media: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Create the .vista directory structure.
|
|
25
|
+
*/
|
|
26
|
+
export declare function createVistaDirectories(cwd: string): VistaDirs;
|
|
27
|
+
export interface BuildManifest {
|
|
28
|
+
buildId: string;
|
|
29
|
+
polyfillFiles: string[];
|
|
30
|
+
devFiles: string[];
|
|
31
|
+
lowPriorityFiles: string[];
|
|
32
|
+
rootMainFiles: string[];
|
|
33
|
+
pages: Record<string, string[]>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Generate build-manifest.json
|
|
37
|
+
*/
|
|
38
|
+
export declare function generateBuildManifest(vistaDir: string, buildId: string, pages?: Record<string, string[]>): BuildManifest;
|
|
39
|
+
export interface RouteInfo {
|
|
40
|
+
page: string;
|
|
41
|
+
regex: string;
|
|
42
|
+
routeKeys: Record<string, string>;
|
|
43
|
+
namedRegex?: string;
|
|
44
|
+
}
|
|
45
|
+
export interface RoutesManifest {
|
|
46
|
+
version: number;
|
|
47
|
+
basePath: string;
|
|
48
|
+
redirects: any[];
|
|
49
|
+
rewrites: any[];
|
|
50
|
+
headers: any[];
|
|
51
|
+
staticRoutes: RouteInfo[];
|
|
52
|
+
dynamicRoutes: RouteInfo[];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Generate routes-manifest.json from route tree.
|
|
56
|
+
*/
|
|
57
|
+
export declare function generateRoutesManifest(vistaDir: string, staticRoutes?: RouteInfo[], dynamicRoutes?: RouteInfo[]): RoutesManifest;
|
|
58
|
+
export interface ClientComponentInfo {
|
|
59
|
+
filePath: string;
|
|
60
|
+
chunkName: string;
|
|
61
|
+
exports: string[];
|
|
62
|
+
}
|
|
63
|
+
export interface ClientComponentsManifest {
|
|
64
|
+
buildId: string;
|
|
65
|
+
clientModules: Record<string, ClientComponentInfo>;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Generate manifest of client components (files with 'client load').
|
|
69
|
+
*/
|
|
70
|
+
export declare function generateClientComponentsManifest(vistaDir: string, buildId: string, clientModules?: Record<string, ClientComponentInfo>): ClientComponentsManifest;
|
|
71
|
+
export interface ServerComponentInfo {
|
|
72
|
+
filePath: string;
|
|
73
|
+
hasMetadata: boolean;
|
|
74
|
+
hasGenerateMetadata: boolean;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Generate manifest of server components.
|
|
78
|
+
*/
|
|
79
|
+
export declare function generateServerComponentsManifest(vistaDir: string, serverModules?: Record<string, ServerComponentInfo>): void;
|
|
80
|
+
/**
|
|
81
|
+
* Get Webpack cache configuration for persistent caching.
|
|
82
|
+
*/
|
|
83
|
+
export declare function getWebpackCacheConfig(vistaDir: string, buildId: string, name: string): {
|
|
84
|
+
type: "filesystem";
|
|
85
|
+
version: string;
|
|
86
|
+
cacheDirectory: string;
|
|
87
|
+
name: string;
|
|
88
|
+
buildDependencies: {
|
|
89
|
+
config: string[];
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Clean old cache entries (keeps last N builds).
|
|
94
|
+
*/
|
|
95
|
+
export declare function cleanOldCache(vistaDir: string, keepBuilds?: number): void;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Vista Build Utilities
|
|
4
|
+
*
|
|
5
|
+
* Generates build manifests, BUILD_ID, and manages .vista output structure.
|
|
6
|
+
*/
|
|
7
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
8
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
9
|
+
};
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.generateBuildId = generateBuildId;
|
|
12
|
+
exports.getBuildId = getBuildId;
|
|
13
|
+
exports.createVistaDirectories = createVistaDirectories;
|
|
14
|
+
exports.generateBuildManifest = generateBuildManifest;
|
|
15
|
+
exports.generateRoutesManifest = generateRoutesManifest;
|
|
16
|
+
exports.generateClientComponentsManifest = generateClientComponentsManifest;
|
|
17
|
+
exports.generateServerComponentsManifest = generateServerComponentsManifest;
|
|
18
|
+
exports.getWebpackCacheConfig = getWebpackCacheConfig;
|
|
19
|
+
exports.cleanOldCache = cleanOldCache;
|
|
20
|
+
const fs_1 = __importDefault(require("fs"));
|
|
21
|
+
const path_1 = __importDefault(require("path"));
|
|
22
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
23
|
+
// ============================================================================
|
|
24
|
+
// BUILD_ID Generation
|
|
25
|
+
// ============================================================================
|
|
26
|
+
/**
|
|
27
|
+
* Generate a unique build ID based on timestamp and random bytes.
|
|
28
|
+
*/
|
|
29
|
+
function generateBuildId() {
|
|
30
|
+
const timestamp = Date.now().toString(36);
|
|
31
|
+
const random = crypto_1.default.randomBytes(4).toString('hex');
|
|
32
|
+
return `${timestamp}-${random}`;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Read existing BUILD_ID or generate a new one.
|
|
36
|
+
*/
|
|
37
|
+
function getBuildId(vistaDir, forceNew = false) {
|
|
38
|
+
const buildIdPath = path_1.default.join(vistaDir, 'BUILD_ID');
|
|
39
|
+
if (!forceNew && fs_1.default.existsSync(buildIdPath)) {
|
|
40
|
+
return fs_1.default.readFileSync(buildIdPath, 'utf-8').trim();
|
|
41
|
+
}
|
|
42
|
+
const buildId = generateBuildId();
|
|
43
|
+
fs_1.default.mkdirSync(vistaDir, { recursive: true });
|
|
44
|
+
fs_1.default.writeFileSync(buildIdPath, buildId);
|
|
45
|
+
return buildId;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Create the .vista directory structure.
|
|
49
|
+
*/
|
|
50
|
+
function createVistaDirectories(cwd) {
|
|
51
|
+
const root = path_1.default.join(cwd, '.vista');
|
|
52
|
+
const dirs = {
|
|
53
|
+
root,
|
|
54
|
+
cache: path_1.default.join(root, 'cache'),
|
|
55
|
+
server: path_1.default.join(root, 'server'),
|
|
56
|
+
static: path_1.default.join(root, 'static'),
|
|
57
|
+
chunks: path_1.default.join(root, 'static', 'chunks'),
|
|
58
|
+
css: path_1.default.join(root, 'static', 'css'),
|
|
59
|
+
media: path_1.default.join(root, 'static', 'media'),
|
|
60
|
+
};
|
|
61
|
+
// Create all directories
|
|
62
|
+
Object.values(dirs).forEach(dir => {
|
|
63
|
+
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
64
|
+
});
|
|
65
|
+
// Create cache subdirectories
|
|
66
|
+
fs_1.default.mkdirSync(path_1.default.join(dirs.cache, 'webpack'), { recursive: true });
|
|
67
|
+
fs_1.default.mkdirSync(path_1.default.join(dirs.cache, 'swc'), { recursive: true });
|
|
68
|
+
fs_1.default.mkdirSync(path_1.default.join(dirs.cache, 'images'), { recursive: true });
|
|
69
|
+
// Create server subdirectories
|
|
70
|
+
fs_1.default.mkdirSync(path_1.default.join(dirs.server, 'app'), { recursive: true });
|
|
71
|
+
fs_1.default.mkdirSync(path_1.default.join(dirs.server, 'chunks'), { recursive: true });
|
|
72
|
+
return dirs;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Generate build-manifest.json
|
|
76
|
+
*/
|
|
77
|
+
function generateBuildManifest(vistaDir, buildId, pages = {}) {
|
|
78
|
+
const manifest = {
|
|
79
|
+
buildId,
|
|
80
|
+
polyfillFiles: [],
|
|
81
|
+
devFiles: [],
|
|
82
|
+
lowPriorityFiles: [],
|
|
83
|
+
rootMainFiles: [
|
|
84
|
+
'/_vista/static/chunks/webpack.js',
|
|
85
|
+
'/_vista/static/chunks/main.js',
|
|
86
|
+
],
|
|
87
|
+
pages,
|
|
88
|
+
};
|
|
89
|
+
const manifestPath = path_1.default.join(vistaDir, 'build-manifest.json');
|
|
90
|
+
fs_1.default.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
91
|
+
return manifest;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Generate routes-manifest.json from route tree.
|
|
95
|
+
*/
|
|
96
|
+
function generateRoutesManifest(vistaDir, staticRoutes = [], dynamicRoutes = []) {
|
|
97
|
+
const manifest = {
|
|
98
|
+
version: 1,
|
|
99
|
+
basePath: '',
|
|
100
|
+
redirects: [],
|
|
101
|
+
rewrites: [],
|
|
102
|
+
headers: [],
|
|
103
|
+
staticRoutes,
|
|
104
|
+
dynamicRoutes,
|
|
105
|
+
};
|
|
106
|
+
const manifestPath = path_1.default.join(vistaDir, 'routes-manifest.json');
|
|
107
|
+
fs_1.default.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
108
|
+
return manifest;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Generate manifest of client components (files with 'client load').
|
|
112
|
+
*/
|
|
113
|
+
function generateClientComponentsManifest(vistaDir, buildId, clientModules = {}) {
|
|
114
|
+
const manifest = {
|
|
115
|
+
buildId,
|
|
116
|
+
clientModules,
|
|
117
|
+
};
|
|
118
|
+
const manifestPath = path_1.default.join(vistaDir, 'client-components-manifest.json');
|
|
119
|
+
fs_1.default.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
120
|
+
return manifest;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Generate manifest of server components.
|
|
124
|
+
*/
|
|
125
|
+
function generateServerComponentsManifest(vistaDir, serverModules = {}) {
|
|
126
|
+
const manifest = {
|
|
127
|
+
serverModules,
|
|
128
|
+
};
|
|
129
|
+
const manifestPath = path_1.default.join(vistaDir, 'server', 'server-components-manifest.json');
|
|
130
|
+
fs_1.default.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
131
|
+
}
|
|
132
|
+
// ============================================================================
|
|
133
|
+
// Cache Utilities
|
|
134
|
+
// ============================================================================
|
|
135
|
+
/**
|
|
136
|
+
* Get Webpack cache configuration for persistent caching.
|
|
137
|
+
*/
|
|
138
|
+
function getWebpackCacheConfig(vistaDir, buildId, name) {
|
|
139
|
+
return {
|
|
140
|
+
type: 'filesystem',
|
|
141
|
+
version: buildId,
|
|
142
|
+
cacheDirectory: path_1.default.join(vistaDir, 'cache', 'webpack'),
|
|
143
|
+
name: name,
|
|
144
|
+
buildDependencies: {
|
|
145
|
+
config: [__filename],
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Clean old cache entries (keeps last N builds).
|
|
151
|
+
*/
|
|
152
|
+
function cleanOldCache(vistaDir, keepBuilds = 5) {
|
|
153
|
+
const cacheDir = path_1.default.join(vistaDir, 'cache', 'webpack');
|
|
154
|
+
if (!fs_1.default.existsSync(cacheDir))
|
|
155
|
+
return;
|
|
156
|
+
const entries = fs_1.default.readdirSync(cacheDir)
|
|
157
|
+
.map(name => ({
|
|
158
|
+
name,
|
|
159
|
+
path: path_1.default.join(cacheDir, name),
|
|
160
|
+
stat: fs_1.default.statSync(path_1.default.join(cacheDir, name)),
|
|
161
|
+
}))
|
|
162
|
+
.filter(e => e.stat.isDirectory())
|
|
163
|
+
.sort((a, b) => b.stat.mtimeMs - a.stat.mtimeMs);
|
|
164
|
+
// Remove old cache directories
|
|
165
|
+
entries.slice(keepBuilds).forEach(entry => {
|
|
166
|
+
fs_1.default.rmSync(entry.path, { recursive: true, force: true });
|
|
167
|
+
});
|
|
168
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client Component Manifest Generator
|
|
3
|
+
*
|
|
4
|
+
* Scans the app directory and builds a manifest of all Client Components.
|
|
5
|
+
* Client components are those with 'client load' directive.
|
|
6
|
+
*
|
|
7
|
+
* The manifest maps component paths to their chunk names for client-side loading.
|
|
8
|
+
*/
|
|
9
|
+
export interface ClientComponentEntry {
|
|
10
|
+
/** Unique ID for this component */
|
|
11
|
+
id: string;
|
|
12
|
+
/** Relative path from app directory */
|
|
13
|
+
path: string;
|
|
14
|
+
/** Absolute file path */
|
|
15
|
+
absolutePath: string;
|
|
16
|
+
/** Generated chunk name */
|
|
17
|
+
chunkName: string;
|
|
18
|
+
/** Exported names from this module */
|
|
19
|
+
exports: string[];
|
|
20
|
+
/** Is async/lazy loaded */
|
|
21
|
+
async: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface ClientManifest {
|
|
24
|
+
/** Build ID for cache busting */
|
|
25
|
+
buildId: string;
|
|
26
|
+
/** Map of module ID to client component info */
|
|
27
|
+
clientModules: Record<string, ClientComponentEntry>;
|
|
28
|
+
/** Map of module path to module ID (for lookups) */
|
|
29
|
+
pathToId: Record<string, string>;
|
|
30
|
+
/** SSR module mapping (server paths to client chunks) */
|
|
31
|
+
ssrModuleMapping: Record<string, string>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Generate the client component manifest
|
|
35
|
+
*/
|
|
36
|
+
export declare function generateClientManifest(cwd: string, appDir: string): ClientManifest;
|
|
37
|
+
/**
|
|
38
|
+
* Get client component info by module ID
|
|
39
|
+
*/
|
|
40
|
+
export declare function getClientComponent(manifest: ClientManifest, moduleId: string): ClientComponentEntry | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Get client component by file path
|
|
43
|
+
*/
|
|
44
|
+
export declare function getClientComponentByPath(manifest: ClientManifest, filePath: string): ClientComponentEntry | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* Check if a path is a client component
|
|
47
|
+
*/
|
|
48
|
+
export declare function isClientComponentPath(manifest: ClientManifest, filePath: string): boolean;
|
|
@@ -0,0 +1,191 @@
|
|
|
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 'client load' 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.generateClientManifest = generateClientManifest;
|
|
15
|
+
exports.getClientComponent = getClientComponent;
|
|
16
|
+
exports.getClientComponentByPath = getClientComponentByPath;
|
|
17
|
+
exports.isClientComponentPath = isClientComponentPath;
|
|
18
|
+
const fs_1 = __importDefault(require("fs"));
|
|
19
|
+
const path_1 = __importDefault(require("path"));
|
|
20
|
+
// Try to load Rust NAPI bindings
|
|
21
|
+
let rustNative = null;
|
|
22
|
+
try {
|
|
23
|
+
const possiblePaths = [
|
|
24
|
+
path_1.default.resolve(__dirname, '../../../../../crates/vista-napi'),
|
|
25
|
+
path_1.default.resolve(__dirname, '../../../../crates/vista-napi'),
|
|
26
|
+
];
|
|
27
|
+
for (const p of possiblePaths) {
|
|
28
|
+
try {
|
|
29
|
+
rustNative = require(p);
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
catch (e) {
|
|
33
|
+
// Try next
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch (e) {
|
|
38
|
+
// Fallback to JS
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Check if source has 'client load' directive
|
|
42
|
+
*/
|
|
43
|
+
function hasClientDirective(source) {
|
|
44
|
+
if (rustNative?.isClientComponent) {
|
|
45
|
+
return rustNative.isClientComponent(source);
|
|
46
|
+
}
|
|
47
|
+
const trimmed = source.trim();
|
|
48
|
+
return trimmed.startsWith("'client load'") || trimmed.startsWith('"client load"');
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Extract export names from source (simple regex approach)
|
|
52
|
+
*/
|
|
53
|
+
function extractExports(source) {
|
|
54
|
+
const exports = [];
|
|
55
|
+
// Default export
|
|
56
|
+
if (/export\s+default\s+/.test(source)) {
|
|
57
|
+
exports.push('default');
|
|
58
|
+
}
|
|
59
|
+
// Named exports: export function Name, export const Name, export class Name
|
|
60
|
+
const namedExportRegex = /export\s+(?:async\s+)?(?:function|const|let|var|class)\s+([A-Z][a-zA-Z0-9_]*)/g;
|
|
61
|
+
let match;
|
|
62
|
+
while ((match = namedExportRegex.exec(source)) !== null) {
|
|
63
|
+
exports.push(match[1]);
|
|
64
|
+
}
|
|
65
|
+
// Export { Name1, Name2 }
|
|
66
|
+
const reExportRegex = /export\s+\{([^}]+)\}/g;
|
|
67
|
+
while ((match = reExportRegex.exec(source)) !== null) {
|
|
68
|
+
const names = match[1]
|
|
69
|
+
.split(',')
|
|
70
|
+
.map((n) => n
|
|
71
|
+
.trim()
|
|
72
|
+
.split(/\s+as\s+/)
|
|
73
|
+
.pop()
|
|
74
|
+
?.trim())
|
|
75
|
+
.filter(Boolean);
|
|
76
|
+
exports.push(...names);
|
|
77
|
+
}
|
|
78
|
+
return [...new Set(exports)];
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Generate a unique chunk name for a component
|
|
82
|
+
*/
|
|
83
|
+
function generateChunkName(relativePath) {
|
|
84
|
+
return relativePath
|
|
85
|
+
.replace(/\\/g, '/')
|
|
86
|
+
.replace(/\.[jt]sx?$/, '')
|
|
87
|
+
.replace(/[^a-zA-Z0-9]/g, '_')
|
|
88
|
+
.toLowerCase();
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Generate unique module ID
|
|
92
|
+
*/
|
|
93
|
+
function generateModuleId(relativePath) {
|
|
94
|
+
// Use a hash-like ID for production, readable path for dev
|
|
95
|
+
const normalized = relativePath.replace(/\\/g, '/').replace(/\.[jt]sx?$/, '');
|
|
96
|
+
return `client:${normalized}`;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Scan directory recursively for client components
|
|
100
|
+
*/
|
|
101
|
+
function scanForClientComponents(dir, appDir, components) {
|
|
102
|
+
if (!fs_1.default.existsSync(dir))
|
|
103
|
+
return;
|
|
104
|
+
const items = fs_1.default.readdirSync(dir, { withFileTypes: true });
|
|
105
|
+
for (const item of items) {
|
|
106
|
+
const fullPath = path_1.default.join(dir, item.name);
|
|
107
|
+
if (item.isDirectory()) {
|
|
108
|
+
if (!item.name.startsWith('.') && item.name !== 'node_modules') {
|
|
109
|
+
scanForClientComponents(fullPath, appDir, components);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
else if (item.isFile()) {
|
|
113
|
+
const ext = path_1.default.extname(item.name);
|
|
114
|
+
if (!['.tsx', '.ts', '.jsx', '.js'].includes(ext))
|
|
115
|
+
continue;
|
|
116
|
+
try {
|
|
117
|
+
const source = fs_1.default.readFileSync(fullPath, 'utf-8');
|
|
118
|
+
if (hasClientDirective(source)) {
|
|
119
|
+
const relativePath = path_1.default.relative(appDir, fullPath);
|
|
120
|
+
const moduleId = generateModuleId(relativePath);
|
|
121
|
+
components.push({
|
|
122
|
+
id: moduleId,
|
|
123
|
+
path: relativePath,
|
|
124
|
+
absolutePath: fullPath,
|
|
125
|
+
chunkName: generateChunkName(relativePath),
|
|
126
|
+
exports: extractExports(source),
|
|
127
|
+
async: false,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
catch (e) {
|
|
132
|
+
console.warn(`[Vista RSC] Failed to read ${fullPath}:`, e);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Generate the client component manifest
|
|
139
|
+
*/
|
|
140
|
+
function generateClientManifest(cwd, appDir) {
|
|
141
|
+
const components = [];
|
|
142
|
+
scanForClientComponents(appDir, appDir, components);
|
|
143
|
+
const clientModules = {};
|
|
144
|
+
const pathToId = {};
|
|
145
|
+
const ssrModuleMapping = {};
|
|
146
|
+
for (const component of components) {
|
|
147
|
+
clientModules[component.id] = component;
|
|
148
|
+
pathToId[component.path] = component.id;
|
|
149
|
+
pathToId[component.absolutePath] = component.id;
|
|
150
|
+
// Map server path to client chunk for SSR
|
|
151
|
+
ssrModuleMapping[component.absolutePath] = `/_vista/static/chunks/${component.chunkName}.js`;
|
|
152
|
+
}
|
|
153
|
+
// Get or generate build ID
|
|
154
|
+
const buildIdPath = path_1.default.join(cwd, '.vista', 'BUILD_ID');
|
|
155
|
+
let buildId = 'dev';
|
|
156
|
+
try {
|
|
157
|
+
if (fs_1.default.existsSync(buildIdPath)) {
|
|
158
|
+
buildId = fs_1.default.readFileSync(buildIdPath, 'utf-8').trim();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
catch (e) {
|
|
162
|
+
// Use dev
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
buildId,
|
|
166
|
+
clientModules,
|
|
167
|
+
pathToId,
|
|
168
|
+
ssrModuleMapping,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Get client component info by module ID
|
|
173
|
+
*/
|
|
174
|
+
function getClientComponent(manifest, moduleId) {
|
|
175
|
+
return manifest.clientModules[moduleId];
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Get client component by file path
|
|
179
|
+
*/
|
|
180
|
+
function getClientComponentByPath(manifest, filePath) {
|
|
181
|
+
const moduleId = manifest.pathToId[filePath];
|
|
182
|
+
if (!moduleId)
|
|
183
|
+
return undefined;
|
|
184
|
+
return manifest.clientModules[moduleId];
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Check if a path is a client component
|
|
188
|
+
*/
|
|
189
|
+
function isClientComponentPath(manifest, filePath) {
|
|
190
|
+
return filePath in manifest.pathToId;
|
|
191
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vista Client Reference Plugin
|
|
3
|
+
*
|
|
4
|
+
* Webpack plugin that transforms server component imports in the client bundle.
|
|
5
|
+
*
|
|
6
|
+
* When a client bundle imports a server component, this plugin:
|
|
7
|
+
* 1. Replaces the import with a client reference proxy
|
|
8
|
+
* 2. The proxy throws an error if used on the client (server components can't run on client)
|
|
9
|
+
* 3. For valid patterns (passing server component as children), the reference works
|
|
10
|
+
*
|
|
11
|
+
* This ensures:
|
|
12
|
+
* - Server code never leaks to the client bundle
|
|
13
|
+
* - Server components contribute 0kb to client JavaScript
|
|
14
|
+
* - Clear error messages when misusing server components
|
|
15
|
+
*/
|
|
16
|
+
import webpack from 'webpack';
|
|
17
|
+
export interface ClientReferencePluginOptions {
|
|
18
|
+
/** Path to the app directory */
|
|
19
|
+
appDir: string;
|
|
20
|
+
/** Path to client manifest JSON */
|
|
21
|
+
clientManifestPath: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Client Reference Plugin
|
|
25
|
+
*
|
|
26
|
+
* Transforms imports of server components in the client bundle
|
|
27
|
+
*/
|
|
28
|
+
export declare class ClientReferencePlugin {
|
|
29
|
+
private appDir;
|
|
30
|
+
private clientManifestPath;
|
|
31
|
+
private clientManifest;
|
|
32
|
+
constructor(options: ClientReferencePluginOptions);
|
|
33
|
+
apply(compiler: webpack.Compiler): void;
|
|
34
|
+
private loadManifest;
|
|
35
|
+
private getComponentId;
|
|
36
|
+
private generateRuntimeManifest;
|
|
37
|
+
}
|