@farm.js/plugin 0.1.0-beta.1 → 0.1.0-beta.100
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +25 -95
- package/dist/dev-static.d.ts +8 -0
- package/dist/dev-static.d.ts.map +1 -0
- package/dist/dev-static.js +37 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/middleware/index.d.ts.map +1 -1
- package/dist/middleware/index.js +28 -53
- package/dist/middleware/matching.d.ts +29 -0
- package/dist/middleware/matching.d.ts.map +1 -0
- package/dist/middleware/matching.js +79 -0
- package/dist/rsc/automatic-optimized-boundary.d.ts +11 -0
- package/dist/rsc/automatic-optimized-boundary.d.ts.map +1 -0
- package/dist/rsc/automatic-optimized-boundary.js +162 -0
- package/dist/rsc/compatibility.d.ts +8 -0
- package/dist/rsc/compatibility.d.ts.map +1 -0
- package/dist/rsc/compatibility.js +46 -0
- package/dist/rsc/dev-response.d.ts +3 -0
- package/dist/rsc/dev-response.d.ts.map +1 -0
- package/dist/rsc/dev-response.js +10 -0
- package/dist/rsc/entries/client.d.ts +1 -0
- package/dist/rsc/entries/client.d.ts.map +1 -1
- package/dist/rsc/entries/client.js +42 -5
- package/dist/rsc/entries/error-fallback.d.ts +3 -0
- package/dist/rsc/entries/error-fallback.d.ts.map +1 -0
- package/dist/rsc/entries/error-fallback.js +12 -0
- package/dist/rsc/entries/rsc.d.ts.map +1 -1
- package/dist/rsc/entries/rsc.js +187 -189
- package/dist/rsc/entries/ssr.d.ts.map +1 -1
- package/dist/rsc/entries/ssr.js +44 -74
- package/dist/rsc/index.d.ts +15 -2
- package/dist/rsc/index.d.ts.map +1 -1
- package/dist/rsc/index.js +167 -69
- package/dist/rsc/nitro-build.d.ts.map +1 -1
- package/dist/rsc/nitro-build.js +28 -8
- package/dist/rsc/optimized-boundary.d.ts +10 -1
- package/dist/rsc/optimized-boundary.d.ts.map +1 -1
- package/dist/rsc/optimized-boundary.js +229 -1
- package/dist/rsc/route-action-transform.d.ts +11 -0
- package/dist/rsc/route-action-transform.d.ts.map +1 -0
- package/dist/rsc/route-action-transform.js +369 -0
- package/dist/rsc/server-fn-transform.js +1 -1
- package/dist/rsc/test-fixture-dependencies.d.ts +2 -0
- package/dist/rsc/test-fixture-dependencies.d.ts.map +1 -0
- package/dist/rsc/test-fixture-dependencies.js +23 -0
- package/dist/rsc/types.d.ts +9 -0
- package/dist/rsc/types.d.ts.map +1 -1
- package/dist/rsc/vite-plugin-nitro.d.ts +20 -7
- package/dist/rsc/vite-plugin-nitro.d.ts.map +1 -1
- package/dist/rsc/vite-plugin-nitro.js +51 -66
- package/package.json +15 -8
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
const ROUTE_FACTORY_IMPORT_RE = /\bimport\s+(?:type\s+)?(?:[A-Za-z_$][\w$]*\s*,\s*)?(\{[^}]*\})\s+from\s*["']@farm.js\/core(?:\/routes)?["']\s*;?/g;
|
|
2
|
+
const EXPORTED_ROUTE_RE = /\bexport\s+(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*([A-Za-z_$][\w$]*)\s*\(/g;
|
|
3
|
+
const IMPORT_RE = /\bimport\s+(?!type\b)([\s\S]*?)\s+from\s*(["'][^"']+["'])\s*;?/g;
|
|
4
|
+
const IDENTIFIER_RE = /^[A-Za-z_$][\w$]*$/;
|
|
5
|
+
const MODULE_EXT_RE = /\.[cm]?[jt]sx?$/;
|
|
6
|
+
/**
|
|
7
|
+
* Replace a programmatic route imported by the browser with a small action-only
|
|
8
|
+
* proxy. Route loaders, components, database imports, and other server code do
|
|
9
|
+
* not enter the client graph.
|
|
10
|
+
*/
|
|
11
|
+
export function transformFarmRouteActionClients(code, id) {
|
|
12
|
+
if (!isTransformableModule(id) || !code.includes("createRoute") || !code.includes("actions")) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
const routeFactories = findRouteFactoryImportNames(code);
|
|
16
|
+
if (routeFactories.size === 0)
|
|
17
|
+
return null;
|
|
18
|
+
const routes = findActionRoutes(code, routeFactories, id);
|
|
19
|
+
if (routes.length === 0)
|
|
20
|
+
return null;
|
|
21
|
+
const importStatements = findRuntimeImports(code);
|
|
22
|
+
const requiredImports = new Set();
|
|
23
|
+
for (const route of routes) {
|
|
24
|
+
for (const action of route.actions) {
|
|
25
|
+
const statement = importStatements.get(action.local);
|
|
26
|
+
if (!statement) {
|
|
27
|
+
throw new Error(`[Farm.js] Route "${route.exportName}" action "${action.name}" in ${id} must reference ` +
|
|
28
|
+
"a server function imported from another module. Define and export createServerFn in an actions module, then import it into the route.");
|
|
29
|
+
}
|
|
30
|
+
requiredImports.add(statement);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const output = [
|
|
34
|
+
...requiredImports,
|
|
35
|
+
...routes.map((route) => generateRouteActionProxy(route)),
|
|
36
|
+
...findRouteDefaultExports(code, routes),
|
|
37
|
+
].join("\n");
|
|
38
|
+
return {
|
|
39
|
+
code: `${output}\n`,
|
|
40
|
+
routes: routes.map((route) => route.exportName),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function findRouteFactoryImportNames(code) {
|
|
44
|
+
const names = new Set();
|
|
45
|
+
for (const match of code.matchAll(ROUTE_FACTORY_IMPORT_RE)) {
|
|
46
|
+
const namedImports = (match[1] ?? "").slice(1, -1).split(",");
|
|
47
|
+
for (const specifier of namedImports) {
|
|
48
|
+
const normalized = specifier.trim().replace(/^type\s+/, "");
|
|
49
|
+
const specifierMatch = normalized.match(/^createRoute(?:\s+as\s+([A-Za-z_$][\w$]*))?$/);
|
|
50
|
+
if (specifierMatch)
|
|
51
|
+
names.add(specifierMatch[1] ?? "createRoute");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return names;
|
|
55
|
+
}
|
|
56
|
+
function findActionRoutes(code, factories, id) {
|
|
57
|
+
const routes = [];
|
|
58
|
+
for (const match of code.matchAll(EXPORTED_ROUTE_RE)) {
|
|
59
|
+
const exportName = match[1];
|
|
60
|
+
const calleeName = match[2];
|
|
61
|
+
if (!exportName || !calleeName || !factories.has(calleeName))
|
|
62
|
+
continue;
|
|
63
|
+
const openParen = (match.index ?? 0) + match[0].length - 1;
|
|
64
|
+
const closeParen = findMatchingDelimiter(code, openParen, "(", ")");
|
|
65
|
+
if (closeParen === -1)
|
|
66
|
+
continue;
|
|
67
|
+
const args = splitTopLevel(code, openParen + 1, closeParen);
|
|
68
|
+
if (args.length < 2)
|
|
69
|
+
continue;
|
|
70
|
+
const pathSource = readSegment(code, args[0]);
|
|
71
|
+
if (!isQuotedString(pathSource)) {
|
|
72
|
+
throw new Error(`[Farm.js] Route "${exportName}" in ${id} must use a static string path before its actions can be imported by a Client Component.`);
|
|
73
|
+
}
|
|
74
|
+
const options = readSegment(code, args[1]);
|
|
75
|
+
if (!options.startsWith("{") || !options.endsWith("}"))
|
|
76
|
+
continue;
|
|
77
|
+
const properties = parseObjectProperties(options.slice(1, -1));
|
|
78
|
+
const actionsSource = properties.get("actions");
|
|
79
|
+
if (!actionsSource)
|
|
80
|
+
continue;
|
|
81
|
+
if (!actionsSource.startsWith("{") || !actionsSource.endsWith("}")) {
|
|
82
|
+
throw new Error(`[Farm.js] Route "${exportName}" actions in ${id} must be an object literal so Farm can generate its client proxy.`);
|
|
83
|
+
}
|
|
84
|
+
const actions = parseActionProperties(actionsSource.slice(1, -1), exportName, id);
|
|
85
|
+
if (actions.length === 0)
|
|
86
|
+
continue;
|
|
87
|
+
const defaultSource = properties.get("defaultAction");
|
|
88
|
+
const defaultAction = defaultSource
|
|
89
|
+
? parseStringValue(defaultSource, exportName, id)
|
|
90
|
+
: actions[0].name;
|
|
91
|
+
if (!actions.some((action) => action.name === defaultAction)) {
|
|
92
|
+
throw new Error(`[Farm.js] Route "${exportName}" defaultAction "${defaultAction}" in ${id} does not match a declared action.`);
|
|
93
|
+
}
|
|
94
|
+
routes.push({ exportName, pathSource, actions, defaultAction });
|
|
95
|
+
}
|
|
96
|
+
return routes;
|
|
97
|
+
}
|
|
98
|
+
function parseActionProperties(source, routeName, id) {
|
|
99
|
+
const properties = parseObjectProperties(source, true);
|
|
100
|
+
const actions = [];
|
|
101
|
+
for (const [name, value] of properties) {
|
|
102
|
+
const local = value || name;
|
|
103
|
+
if (!IDENTIFIER_RE.test(name) || !IDENTIFIER_RE.test(local)) {
|
|
104
|
+
throw new Error(`[Farm.js] Route "${routeName}" actions in ${id} must use identifier entries such as { update } or { update: updateProduct }.`);
|
|
105
|
+
}
|
|
106
|
+
actions.push({ name, local });
|
|
107
|
+
}
|
|
108
|
+
return actions;
|
|
109
|
+
}
|
|
110
|
+
function parseObjectProperties(source, allowShorthand = false) {
|
|
111
|
+
const properties = new Map();
|
|
112
|
+
for (const segment of splitTopLevel(source, 0, source.length)) {
|
|
113
|
+
const entry = readSegment(source, segment);
|
|
114
|
+
if (!entry)
|
|
115
|
+
continue;
|
|
116
|
+
if (entry.startsWith("...")) {
|
|
117
|
+
properties.set(entry, "");
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
const colon = findTopLevelColon(entry);
|
|
121
|
+
if (colon === -1) {
|
|
122
|
+
if (allowShorthand)
|
|
123
|
+
properties.set(entry, "");
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const keySource = entry.slice(0, colon).trim();
|
|
127
|
+
const value = entry.slice(colon + 1).trim();
|
|
128
|
+
const key = isQuotedString(keySource) ? unquote(keySource) : keySource;
|
|
129
|
+
properties.set(key, value);
|
|
130
|
+
}
|
|
131
|
+
return properties;
|
|
132
|
+
}
|
|
133
|
+
function findRuntimeImports(code) {
|
|
134
|
+
const imports = new Map();
|
|
135
|
+
for (const match of code.matchAll(IMPORT_RE)) {
|
|
136
|
+
const clause = (match[1] ?? "").trim();
|
|
137
|
+
const statement = match[0];
|
|
138
|
+
const namedStart = clause.indexOf("{");
|
|
139
|
+
const namedEnd = clause.lastIndexOf("}");
|
|
140
|
+
if (namedStart > -1 && namedEnd > namedStart) {
|
|
141
|
+
for (const specifier of clause.slice(namedStart + 1, namedEnd).split(",")) {
|
|
142
|
+
const normalized = specifier.trim().replace(/^type\s+/, "");
|
|
143
|
+
if (!normalized || specifier.trim().startsWith("type "))
|
|
144
|
+
continue;
|
|
145
|
+
const parts = normalized.split(/\s+as\s+/);
|
|
146
|
+
const local = parts[1] ?? parts[0];
|
|
147
|
+
if (local && IDENTIFIER_RE.test(local))
|
|
148
|
+
imports.set(local, statement);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const defaultImport = clause
|
|
152
|
+
.slice(0, namedStart === -1 ? clause.length : namedStart)
|
|
153
|
+
.replace(/,$/, "")
|
|
154
|
+
.trim();
|
|
155
|
+
if (IDENTIFIER_RE.test(defaultImport))
|
|
156
|
+
imports.set(defaultImport, statement);
|
|
157
|
+
}
|
|
158
|
+
return imports;
|
|
159
|
+
}
|
|
160
|
+
function generateRouteActionProxy(route) {
|
|
161
|
+
const actions = route.actions
|
|
162
|
+
.map((action) => `${JSON.stringify(action.name)}: ${action.local}`)
|
|
163
|
+
.join(", ");
|
|
164
|
+
const defaultAction = route.actions.find((action) => action.name === route.defaultAction);
|
|
165
|
+
return `export const ${route.exportName} = Object.freeze({
|
|
166
|
+
__farmRouteActionTarget: true,
|
|
167
|
+
path: ${route.pathSource},
|
|
168
|
+
actions: Object.freeze({ ${actions} }),
|
|
169
|
+
defaultAction: ${JSON.stringify(route.defaultAction)},
|
|
170
|
+
action: ${defaultAction.local},
|
|
171
|
+
});`;
|
|
172
|
+
}
|
|
173
|
+
function findRouteDefaultExports(code, routes) {
|
|
174
|
+
const exports = [];
|
|
175
|
+
for (const route of routes) {
|
|
176
|
+
const defaultExport = new RegExp(`\\bexport\\s+default\\s+${escapeRegExp(route.exportName)}\\s*;?`);
|
|
177
|
+
if (defaultExport.test(code))
|
|
178
|
+
exports.push(`export default ${route.exportName};`);
|
|
179
|
+
}
|
|
180
|
+
return exports;
|
|
181
|
+
}
|
|
182
|
+
function splitTopLevel(source, start, end) {
|
|
183
|
+
const segments = [];
|
|
184
|
+
let segmentStart = start;
|
|
185
|
+
let parens = 0;
|
|
186
|
+
let braces = 0;
|
|
187
|
+
let brackets = 0;
|
|
188
|
+
let quote = null;
|
|
189
|
+
let escaped = false;
|
|
190
|
+
let lineComment = false;
|
|
191
|
+
let blockComment = false;
|
|
192
|
+
for (let index = start; index < end; index++) {
|
|
193
|
+
const char = source[index];
|
|
194
|
+
const next = source[index + 1];
|
|
195
|
+
if (lineComment) {
|
|
196
|
+
if (char === "\n" || char === "\r")
|
|
197
|
+
lineComment = false;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (blockComment) {
|
|
201
|
+
if (char === "*" && next === "/") {
|
|
202
|
+
blockComment = false;
|
|
203
|
+
index++;
|
|
204
|
+
}
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
if (quote) {
|
|
208
|
+
if (escaped)
|
|
209
|
+
escaped = false;
|
|
210
|
+
else if (char === "\\")
|
|
211
|
+
escaped = true;
|
|
212
|
+
else if (char === quote)
|
|
213
|
+
quote = null;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
if (char === "/" && next === "/") {
|
|
217
|
+
lineComment = true;
|
|
218
|
+
index++;
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
if (char === "/" && next === "*") {
|
|
222
|
+
blockComment = true;
|
|
223
|
+
index++;
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
if (char === "'" || char === '"' || char === "`") {
|
|
227
|
+
quote = char;
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
if (char === "(")
|
|
231
|
+
parens++;
|
|
232
|
+
else if (char === ")")
|
|
233
|
+
parens--;
|
|
234
|
+
else if (char === "{")
|
|
235
|
+
braces++;
|
|
236
|
+
else if (char === "}")
|
|
237
|
+
braces--;
|
|
238
|
+
else if (char === "[")
|
|
239
|
+
brackets++;
|
|
240
|
+
else if (char === "]")
|
|
241
|
+
brackets--;
|
|
242
|
+
else if (char === "," && parens === 0 && braces === 0 && brackets === 0) {
|
|
243
|
+
segments.push([segmentStart, index]);
|
|
244
|
+
segmentStart = index + 1;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
segments.push([segmentStart, end]);
|
|
248
|
+
return segments;
|
|
249
|
+
}
|
|
250
|
+
function findTopLevelColon(source) {
|
|
251
|
+
const segments = splitTopLevel(source, 0, source.length);
|
|
252
|
+
if (segments.length !== 1)
|
|
253
|
+
return -1;
|
|
254
|
+
let parens = 0;
|
|
255
|
+
let braces = 0;
|
|
256
|
+
let brackets = 0;
|
|
257
|
+
let quote = null;
|
|
258
|
+
let escaped = false;
|
|
259
|
+
for (let index = 0; index < source.length; index++) {
|
|
260
|
+
const char = source[index];
|
|
261
|
+
if (quote) {
|
|
262
|
+
if (escaped)
|
|
263
|
+
escaped = false;
|
|
264
|
+
else if (char === "\\")
|
|
265
|
+
escaped = true;
|
|
266
|
+
else if (char === quote)
|
|
267
|
+
quote = null;
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
if (char === "'" || char === '"' || char === "`") {
|
|
271
|
+
quote = char;
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
if (char === "(")
|
|
275
|
+
parens++;
|
|
276
|
+
else if (char === ")")
|
|
277
|
+
parens--;
|
|
278
|
+
else if (char === "{")
|
|
279
|
+
braces++;
|
|
280
|
+
else if (char === "}")
|
|
281
|
+
braces--;
|
|
282
|
+
else if (char === "[")
|
|
283
|
+
brackets++;
|
|
284
|
+
else if (char === "]")
|
|
285
|
+
brackets--;
|
|
286
|
+
else if (char === ":" && parens === 0 && braces === 0 && brackets === 0)
|
|
287
|
+
return index;
|
|
288
|
+
}
|
|
289
|
+
return -1;
|
|
290
|
+
}
|
|
291
|
+
function findMatchingDelimiter(source, openIndex, open, close) {
|
|
292
|
+
let depth = 0;
|
|
293
|
+
let quote = null;
|
|
294
|
+
let lineComment = false;
|
|
295
|
+
let blockComment = false;
|
|
296
|
+
let escaped = false;
|
|
297
|
+
for (let index = openIndex; index < source.length; index++) {
|
|
298
|
+
const char = source[index];
|
|
299
|
+
const next = source[index + 1];
|
|
300
|
+
if (lineComment) {
|
|
301
|
+
if (char === "\n" || char === "\r")
|
|
302
|
+
lineComment = false;
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
if (blockComment) {
|
|
306
|
+
if (char === "*" && next === "/") {
|
|
307
|
+
blockComment = false;
|
|
308
|
+
index++;
|
|
309
|
+
}
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
if (quote) {
|
|
313
|
+
if (escaped)
|
|
314
|
+
escaped = false;
|
|
315
|
+
else if (char === "\\")
|
|
316
|
+
escaped = true;
|
|
317
|
+
else if (char === quote)
|
|
318
|
+
quote = null;
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
if (char === "/" && next === "/") {
|
|
322
|
+
lineComment = true;
|
|
323
|
+
index++;
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
if (char === "/" && next === "*") {
|
|
327
|
+
blockComment = true;
|
|
328
|
+
index++;
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
if (char === "'" || char === '"' || char === "`") {
|
|
332
|
+
quote = char;
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
if (char === open)
|
|
336
|
+
depth++;
|
|
337
|
+
else if (char === close && --depth === 0)
|
|
338
|
+
return index;
|
|
339
|
+
}
|
|
340
|
+
return -1;
|
|
341
|
+
}
|
|
342
|
+
function readSegment(source, segment) {
|
|
343
|
+
return source.slice(segment[0], segment[1]).trim();
|
|
344
|
+
}
|
|
345
|
+
function parseStringValue(source, routeName, id) {
|
|
346
|
+
if (!isQuotedString(source)) {
|
|
347
|
+
throw new Error(`[Farm.js] Route "${routeName}" defaultAction in ${id} must be a static string.`);
|
|
348
|
+
}
|
|
349
|
+
return unquote(source);
|
|
350
|
+
}
|
|
351
|
+
function isQuotedString(value) {
|
|
352
|
+
return (value.length >= 2 &&
|
|
353
|
+
((value.startsWith('"') && value.endsWith('"')) ||
|
|
354
|
+
(value.startsWith("'") && value.endsWith("'"))));
|
|
355
|
+
}
|
|
356
|
+
function unquote(value) {
|
|
357
|
+
const quote = value[0];
|
|
358
|
+
const body = value.slice(1, -1);
|
|
359
|
+
if (quote === '"')
|
|
360
|
+
return JSON.parse(value);
|
|
361
|
+
return body.replace(/\\'/g, "'").replace(/\\\\/g, "\\");
|
|
362
|
+
}
|
|
363
|
+
function isTransformableModule(id) {
|
|
364
|
+
const cleanId = id.split("?", 1)[0];
|
|
365
|
+
return MODULE_EXT_RE.test(cleanId) && !/\.d\.[cm]?ts$/.test(cleanId);
|
|
366
|
+
}
|
|
367
|
+
function escapeRegExp(value) {
|
|
368
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
369
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const SERVER_FUNCTION_FACTORY_IMPORT_RE = /\bimport\s+(?:type\s+)?(?:[A-Za-z_$][\w$]*\s*,\s*)?(\{[^}]*\})\s+from\s*["']@farm.js\/core(?:\/(?:server-fn|server-query))?["']\s*;?/g;
|
|
2
|
-
const EXPORT_SERVER_FUNCTION_FACTORY_RE = /\bexport\s+(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*([A-Za-z_$][\w$]*)\s*\(/g;
|
|
2
|
+
const EXPORT_SERVER_FUNCTION_FACTORY_RE = /\bexport\s+(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*([A-Za-z_$][\w$]*)\s*(?:<[^<>]*(?:<[^<>]*>[^<>]*)*>)?\s*\(/g;
|
|
3
3
|
const MODULE_EXT_RE = /\.[cm]?[jt]sx?$/;
|
|
4
4
|
const DECLARATION_RE = /(^|\n)\s*["']([^"']+)["']\s*;?/g;
|
|
5
5
|
export function transformFarmServerFns(code, id) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-fixture-dependencies.d.ts","sourceRoot":"","sources":["../../src/rsc/test-fixture-dependencies.ts"],"names":[],"mappings":"AAaA,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAY7D"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, realpathSync, symlinkSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
const RSC_FIXTURE_PACKAGES = [
|
|
5
|
+
"react",
|
|
6
|
+
"react-dom",
|
|
7
|
+
"react-server-dom-webpack",
|
|
8
|
+
"@vitejs/plugin-rsc",
|
|
9
|
+
];
|
|
10
|
+
const repositoryRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../../..");
|
|
11
|
+
export function linkRscFixtureDependencies(root) {
|
|
12
|
+
for (const packageName of RSC_FIXTURE_PACKAGES) {
|
|
13
|
+
const source = [
|
|
14
|
+
path.join(repositoryRoot, "node_modules", packageName),
|
|
15
|
+
path.join(repositoryRoot, "examples/rsc-demo/node_modules", packageName),
|
|
16
|
+
].find((candidate) => existsSync(candidate));
|
|
17
|
+
if (!source)
|
|
18
|
+
throw new Error(`Missing RSC fixture dependency: ${packageName}`);
|
|
19
|
+
const target = path.join(root, "node_modules", packageName);
|
|
20
|
+
mkdirSync(path.dirname(target), { recursive: true });
|
|
21
|
+
symlinkSync(realpathSync(source), target, process.platform === "win32" ? "junction" : "dir");
|
|
22
|
+
}
|
|
23
|
+
}
|
package/dist/rsc/types.d.ts
CHANGED
|
@@ -54,6 +54,8 @@ export interface EntryContext {
|
|
|
54
54
|
outDir: string;
|
|
55
55
|
/** Base URL path, e.g. '/' */
|
|
56
56
|
basePath: string;
|
|
57
|
+
/** Resolved same-origin mount for canonical /api routes. */
|
|
58
|
+
apiBasePath?: string;
|
|
57
59
|
/** Route files subdirectory within srcDir */
|
|
58
60
|
routesDir?: string;
|
|
59
61
|
/** Root-relative Vite URL for an existing global stylesheet. */
|
|
@@ -72,6 +74,13 @@ export interface EntryContext {
|
|
|
72
74
|
deploymentId: string;
|
|
73
75
|
/** Whether debug mode is enabled */
|
|
74
76
|
debug: boolean;
|
|
77
|
+
/** True only for the Vite serve command, never for a production build. */
|
|
78
|
+
development?: boolean;
|
|
79
|
+
/** Generated import/init fragments for `cache.client.adapter` persistence. */
|
|
80
|
+
clientCachePersistence?: {
|
|
81
|
+
imports: string;
|
|
82
|
+
init: string;
|
|
83
|
+
};
|
|
75
84
|
}
|
|
76
85
|
/**
|
|
77
86
|
* Matched route information from the file-based router.
|
package/dist/rsc/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/rsc/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,uBAAuB,EACvB,+BAA+B,EAChC,MAAM,sCAAsC,CAAC;AAE9C;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,yDAAyD;IACzD,aAAa,CAAC,EAAE,uBAAuB,CAAC;IAExC,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;OAIG;IACH,OAAO,CAAC,EAAE;QACR,wCAAwC;QACxC,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,wCAAwC;QACxC,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,2CAA2C;QAC3C,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IAEF;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;IAEf,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;IAEf,8BAA8B;IAC9B,QAAQ,EAAE,MAAM,CAAC;IAEjB,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,gEAAgE;IAChE,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,uFAAuF;IACvF,UAAU,CAAC,EAAE,KAAK,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;IAEH,yCAAyC;IACzC,cAAc,EAAE,OAAO,CAAC;IAExB,wDAAwD;IACxD,aAAa,EAAE,+BAA+B,CAAC;IAE/C,8EAA8E;IAC9E,YAAY,EAAE,MAAM,CAAC;IAErB,oCAAoC;IACpC,KAAK,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/rsc/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,15 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Vite plugin
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
2
|
+
* Vite plugin for the Nitro RSC deployment pipeline. It forces per-environment
|
|
3
|
+
* output dirs (`Step 1`), captures the server (RSC) Rollup bundle in `writeBundle`
|
|
4
|
+
* (`Step 2`), and exposes `runNitroFromBuildApp()`, which builds Nitro from the
|
|
5
|
+
* captured outputs once all environments have finished writing.
|
|
6
|
+
*
|
|
7
|
+
* Farm's RSC builder invokes `runNitroFromBuildApp()` after every environment
|
|
8
|
+
* has written its output, so a single `vite build` still produces the
|
|
9
|
+
* deployment bundle.
|
|
10
|
+
*
|
|
11
|
+
* The plugin no longer triggers Nitro itself from a Rollup hook: the previous
|
|
12
|
+
* `buildEnd` trigger fired before its own environment's `prepareOutDir`/`writeBundle`,
|
|
13
|
+
* so on a rebuild it observed the previous build's stale outputs and built Nitro
|
|
14
|
+
* against them (and set `__FARM_NITRO_PLUGIN_RAN`, suppressing the proper run).
|
|
15
|
+
* Removing it keeps Nitro from running against stale artifacts while the post-app
|
|
16
|
+
* hook preserves the one-command build contract.
|
|
17
|
+
*
|
|
18
|
+
* - Step 1: Force per-environment output dirs to `.nitro/vite/dist/${name}` so Nitro can locate artifacts.
|
|
19
|
+
* - Step 2: Capture the server (RSC) Rollup bundle in `writeBundle`.
|
|
8
20
|
*
|
|
9
21
|
* @example
|
|
10
22
|
* ```ts
|
|
11
|
-
* import nitro from '@farm.js/plugin/rsc
|
|
23
|
+
* import { defineConfig, nitro } from '@farm.js/plugin/rsc'
|
|
12
24
|
* export default defineConfig({
|
|
25
|
+
* srcDir: 'src',
|
|
13
26
|
* plugins: [rsc(), react(), nitro({ server: { environmentName: 'rsc' }, config: { preset: 'vercel' } })],
|
|
14
27
|
* })
|
|
15
28
|
* ```
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vite-plugin-nitro.d.ts","sourceRoot":"","sources":["../../src/rsc/vite-plugin-nitro.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"vite-plugin-nitro.d.ts","sourceRoot":"","sources":["../../src/rsc/vite-plugin-nitro.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAenC,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE;QACP,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,4DAA4D;QAC5D,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,MAAM,CAAC,EAAE;QACP,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAID,MAAM,CAAC,OAAO,UAAU,KAAK,CAAC,OAAO,GAAE,kBAAuB,GAAG,MAAM,CAqEtE;AAED,kFAAkF;AAClF,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAkC1D"}
|
|
@@ -1,15 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Vite plugin
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
2
|
+
* Vite plugin for the Nitro RSC deployment pipeline. It forces per-environment
|
|
3
|
+
* output dirs (`Step 1`), captures the server (RSC) Rollup bundle in `writeBundle`
|
|
4
|
+
* (`Step 2`), and exposes `runNitroFromBuildApp()`, which builds Nitro from the
|
|
5
|
+
* captured outputs once all environments have finished writing.
|
|
6
|
+
*
|
|
7
|
+
* Farm's RSC builder invokes `runNitroFromBuildApp()` after every environment
|
|
8
|
+
* has written its output, so a single `vite build` still produces the
|
|
9
|
+
* deployment bundle.
|
|
10
|
+
*
|
|
11
|
+
* The plugin no longer triggers Nitro itself from a Rollup hook: the previous
|
|
12
|
+
* `buildEnd` trigger fired before its own environment's `prepareOutDir`/`writeBundle`,
|
|
13
|
+
* so on a rebuild it observed the previous build's stale outputs and built Nitro
|
|
14
|
+
* against them (and set `__FARM_NITRO_PLUGIN_RAN`, suppressing the proper run).
|
|
15
|
+
* Removing it keeps Nitro from running against stale artifacts while the post-app
|
|
16
|
+
* hook preserves the one-command build contract.
|
|
17
|
+
*
|
|
18
|
+
* - Step 1: Force per-environment output dirs to `.nitro/vite/dist/${name}` so Nitro can locate artifacts.
|
|
19
|
+
* - Step 2: Capture the server (RSC) Rollup bundle in `writeBundle`.
|
|
8
20
|
*
|
|
9
21
|
* @example
|
|
10
22
|
* ```ts
|
|
11
|
-
* import nitro from '@farm.js/plugin/rsc
|
|
23
|
+
* import { defineConfig, nitro } from '@farm.js/plugin/rsc'
|
|
12
24
|
* export default defineConfig({
|
|
25
|
+
* srcDir: 'src',
|
|
13
26
|
* plugins: [rsc(), react(), nitro({ server: { environmentName: 'rsc' }, config: { preset: 'vercel' } })],
|
|
14
27
|
* })
|
|
15
28
|
* ```
|
|
@@ -18,9 +31,6 @@ import path from "path";
|
|
|
18
31
|
import { buildRscNitro } from "./nitro-build.js";
|
|
19
32
|
import { waitForRscOutputs } from "./nitro-build.js";
|
|
20
33
|
import { resolveRscBuildOutputPath } from "./build-paths.js";
|
|
21
|
-
let nitroRunScheduled = false;
|
|
22
|
-
/** Stored RSC (server) bundle from writeBundle so we can find the entry chunk. */
|
|
23
|
-
let serverBundle = null;
|
|
24
34
|
const NITRO_VITE_DIST = ".nitro/vite/dist";
|
|
25
35
|
export default function nitro(options = {}) {
|
|
26
36
|
const serverEnvName = options.server?.environmentName ?? "rsc";
|
|
@@ -29,12 +39,15 @@ export default function nitro(options = {}) {
|
|
|
29
39
|
let rscOutDir = path.join(NITRO_VITE_DIST, "rsc");
|
|
30
40
|
let ssrOutDir = path.join(NITRO_VITE_DIST, "ssr");
|
|
31
41
|
let clientOutDir = path.join(NITRO_VITE_DIST, "client");
|
|
32
|
-
let
|
|
42
|
+
let clientAssetsDir = "assets";
|
|
33
43
|
return {
|
|
34
44
|
name: "vite-plugin-nitro",
|
|
35
45
|
apply: "build",
|
|
36
46
|
// Step 1: Force per-environment output dirs so Nitro can locate artifacts.
|
|
37
47
|
config() {
|
|
48
|
+
delete globalThis.__FARM_NITRO_SERVER_BUNDLE;
|
|
49
|
+
delete globalThis.__FARM_NITRO_PATHS;
|
|
50
|
+
delete globalThis.__FARM_NITRO_BUILD_PROMISE;
|
|
38
51
|
return {
|
|
39
52
|
environments: {
|
|
40
53
|
rsc: { build: { outDir: path.join(NITRO_VITE_DIST, "rsc") } },
|
|
@@ -50,20 +63,23 @@ export default function nitro(options = {}) {
|
|
|
50
63
|
rscOutDir = envs.rsc.build.outDir;
|
|
51
64
|
ssrOutDir = envs.ssr.build.outDir;
|
|
52
65
|
clientOutDir = envs.client.build.outDir;
|
|
53
|
-
const dir = path.dirname(rscOutDir);
|
|
54
|
-
baseOutDir = path.isAbsolute(dir) ? path.relative(resolvedRoot, dir) || "." : dir;
|
|
55
66
|
}
|
|
56
67
|
else {
|
|
57
|
-
baseOutDir = options.outDir ?? "dist";
|
|
68
|
+
const baseOutDir = options.outDir ?? "dist";
|
|
58
69
|
rscOutDir = path.join(baseOutDir, "rsc");
|
|
59
70
|
ssrOutDir = path.join(baseOutDir, "ssr");
|
|
60
71
|
clientOutDir = path.join(baseOutDir, "client");
|
|
61
72
|
}
|
|
73
|
+
const clientBuildAssetsDir = envs?.client?.build?.assetsDir;
|
|
74
|
+
clientAssetsDir =
|
|
75
|
+
typeof clientBuildAssetsDir === "string" && clientBuildAssetsDir
|
|
76
|
+
? clientBuildAssetsDir
|
|
77
|
+
: "assets";
|
|
62
78
|
},
|
|
63
79
|
// Step 2: Capture the server (RSC) Rollup bundle when that environment writes.
|
|
64
80
|
writeBundle(_options, bundle) {
|
|
65
81
|
if (this.environment?.name === serverEnvName) {
|
|
66
|
-
|
|
82
|
+
delete globalThis.__FARM_NITRO_BUILD_PROMISE;
|
|
67
83
|
globalThis.__FARM_NITRO_SERVER_BUNDLE = bundle;
|
|
68
84
|
globalThis.__FARM_NITRO_PATHS = {
|
|
69
85
|
root: resolvedRoot,
|
|
@@ -72,59 +88,10 @@ export default function nitro(options = {}) {
|
|
|
72
88
|
clientOutDir,
|
|
73
89
|
serverEntryName,
|
|
74
90
|
preset: options.config?.preset ?? process.env.NITRO_PRESET ?? "vercel",
|
|
91
|
+
clientAssetsDir,
|
|
75
92
|
};
|
|
76
93
|
}
|
|
77
94
|
},
|
|
78
|
-
// Run Nitro once all env outputs exist (after step 5). buildEnd runs after each env; only run when all exist.
|
|
79
|
-
async buildEnd() {
|
|
80
|
-
if (nitroRunScheduled)
|
|
81
|
-
return;
|
|
82
|
-
const root = path.resolve(resolvedRoot);
|
|
83
|
-
const { existsSync } = await import("fs");
|
|
84
|
-
await new Promise((r) => setTimeout(r, 800));
|
|
85
|
-
const baseOutDir = rscOutDir.includes(".nitro/vite/dist")
|
|
86
|
-
? NITRO_VITE_DIST
|
|
87
|
-
: path.isAbsolute(path.dirname(rscOutDir))
|
|
88
|
-
? path.relative(root, path.dirname(rscOutDir)) || "."
|
|
89
|
-
: path.dirname(rscOutDir);
|
|
90
|
-
const rscOk = existsSync(resolveRscBuildOutputPath(root, baseOutDir, "rsc", "index.js"));
|
|
91
|
-
const ssrOk = existsSync(resolveRscBuildOutputPath(root, baseOutDir, "ssr", "index.js"));
|
|
92
|
-
const clientOk = existsSync(resolveRscBuildOutputPath(root, baseOutDir, "client", "assets"));
|
|
93
|
-
if (!rscOk || !ssrOk || !clientOk)
|
|
94
|
-
return;
|
|
95
|
-
nitroRunScheduled = true;
|
|
96
|
-
const preset = options.config?.preset ?? process.env.NITRO_PRESET ?? "vercel";
|
|
97
|
-
const run = async () => {
|
|
98
|
-
await waitForRscOutputs(root, baseOutDir, { timeoutMs: 20_000 }).catch(() => {
|
|
99
|
-
// Outputs already verified; proceed (nitro-build stubs manifest if missing)
|
|
100
|
-
});
|
|
101
|
-
let rendererPath = resolveRscBuildOutputPath(root, rscOutDir, "index.js");
|
|
102
|
-
if (serverBundle) {
|
|
103
|
-
const serverEntryChunks = [];
|
|
104
|
-
for (const chunk of Object.values(serverBundle)) {
|
|
105
|
-
if (chunk.type === "chunk" && chunk.isEntry && chunk.fileName) {
|
|
106
|
-
serverEntryChunks.push(chunk);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
const selected = serverEntryName
|
|
110
|
-
? serverEntryChunks.find((c) => (c.name ?? c.fileName) === serverEntryName)
|
|
111
|
-
: serverEntryChunks[0];
|
|
112
|
-
if (selected?.fileName) {
|
|
113
|
-
rendererPath = resolveRscBuildOutputPath(root, rscOutDir, selected.fileName);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
await buildRscNitro({
|
|
117
|
-
root,
|
|
118
|
-
rendererPath,
|
|
119
|
-
publicDir: resolveRscBuildOutputPath(root, clientOutDir),
|
|
120
|
-
ssrPath: resolveRscBuildOutputPath(root, ssrOutDir, "index.js"),
|
|
121
|
-
assetsDir: undefined,
|
|
122
|
-
preset,
|
|
123
|
-
});
|
|
124
|
-
globalThis.__FARM_NITRO_PLUGIN_RAN = true;
|
|
125
|
-
};
|
|
126
|
-
await run();
|
|
127
|
-
},
|
|
128
95
|
};
|
|
129
96
|
}
|
|
130
97
|
/** Called by RSC plugin buildApp (post) to run Nitro with the captured bundle. */
|
|
@@ -133,6 +100,24 @@ export async function runNitroFromBuildApp() {
|
|
|
133
100
|
const bundle = globalThis.__FARM_NITRO_SERVER_BUNDLE;
|
|
134
101
|
if (!paths)
|
|
135
102
|
return;
|
|
103
|
+
const existing = globalThis.__FARM_NITRO_BUILD_PROMISE;
|
|
104
|
+
if (existing) {
|
|
105
|
+
await existing;
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const run = runCapturedNitroBuild(paths, bundle);
|
|
109
|
+
globalThis.__FARM_NITRO_BUILD_PROMISE = run;
|
|
110
|
+
try {
|
|
111
|
+
await run;
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
if (globalThis.__FARM_NITRO_BUILD_PROMISE === run) {
|
|
115
|
+
delete globalThis.__FARM_NITRO_BUILD_PROMISE;
|
|
116
|
+
}
|
|
117
|
+
throw error;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
async function runCapturedNitroBuild(paths, bundle) {
|
|
136
121
|
const root = paths.root;
|
|
137
122
|
const preset = paths.preset;
|
|
138
123
|
const baseOutDir = path.dirname(paths.rscOutDir);
|
|
@@ -157,7 +142,7 @@ export async function runNitroFromBuildApp() {
|
|
|
157
142
|
rendererPath,
|
|
158
143
|
publicDir: resolveRscBuildOutputPath(root, paths.clientOutDir),
|
|
159
144
|
ssrPath: resolveRscBuildOutputPath(root, paths.ssrOutDir, "index.js"),
|
|
160
|
-
assetsDir:
|
|
145
|
+
assetsDir: paths.clientAssetsDir ?? "assets",
|
|
161
146
|
preset,
|
|
162
147
|
});
|
|
163
148
|
}
|