@cedarjs/vite 4.0.1-next.0 → 4.1.0-rc.70
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/apiDevServer.d.ts +18 -0
- package/dist/apiDevServer.d.ts.map +1 -0
- package/dist/apiDevServer.js +335 -0
- package/dist/buildUDApiServer.d.ts +22 -0
- package/dist/buildUDApiServer.d.ts.map +1 -0
- package/dist/buildUDApiServer.js +59 -0
- package/dist/cedar-unified-dev.d.ts +3 -0
- package/dist/cedar-unified-dev.d.ts.map +1 -0
- package/dist/cedar-unified-dev.js +65 -0
- package/dist/cjs/apiDevServer.js +366 -0
- package/dist/cjs/buildUDApiServer.js +93 -0
- package/dist/cjs/cedar-unified-dev.js +88 -0
- package/dist/cjs/index.js +9 -0
- package/dist/cjs/lib/getMergedConfig.js +5 -0
- package/dist/cjs/lib/workspacePackageAliases.js +113 -0
- package/dist/cjs/plugins/vite-plugin-cedar-dev-dispatcher.js +223 -0
- package/dist/cjs/plugins/vite-plugin-cedar-universal-deploy.js +63 -0
- package/dist/cjs/rsc/rscBuildAnalyze.js +2 -0
- package/dist/cjs/rsc/rscBuildForServer.js +2 -0
- package/dist/cjs/rsc/rscBuildForSsr.js +2 -0
- package/dist/cjs/rsc/rscStudioHandlers.js +2 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/lib/getMergedConfig.d.ts.map +1 -1
- package/dist/lib/getMergedConfig.js +5 -0
- package/dist/lib/workspacePackageAliases.d.ts +18 -0
- package/dist/lib/workspacePackageAliases.d.ts.map +1 -0
- package/dist/lib/workspacePackageAliases.js +79 -0
- package/dist/plugins/vite-plugin-cedar-dev-dispatcher.d.ts +3 -0
- package/dist/plugins/vite-plugin-cedar-dev-dispatcher.d.ts.map +1 -0
- package/dist/plugins/vite-plugin-cedar-dev-dispatcher.js +189 -0
- package/dist/plugins/vite-plugin-cedar-universal-deploy.d.ts +6 -0
- package/dist/plugins/vite-plugin-cedar-universal-deploy.d.ts.map +1 -0
- package/dist/plugins/vite-plugin-cedar-universal-deploy.js +39 -0
- package/dist/rsc/rscBuildAnalyze.d.ts.map +1 -1
- package/dist/rsc/rscBuildAnalyze.js +2 -0
- package/dist/rsc/rscBuildForServer.d.ts.map +1 -1
- package/dist/rsc/rscBuildForServer.js +2 -0
- package/dist/rsc/rscBuildForSsr.d.ts.map +1 -1
- package/dist/rsc/rscBuildForSsr.js +2 -0
- package/dist/rsc/rscStudioHandlers.d.ts.map +1 -1
- package/dist/rsc/rscStudioHandlers.js +2 -1
- package/package.json +39 -19
- /package/bins/{rw-vite-build.mjs → cedar-vite-build.mjs} +0 -0
- /package/bins/{rw-vite-dev.mjs → cedar-vite-dev.mjs} +0 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ViteDevServer } from 'vite';
|
|
2
|
+
/**
|
|
3
|
+
* Start the Cedar API dev server using Vite's SSR module runner for HMR.
|
|
4
|
+
*
|
|
5
|
+
* This replaces the previous system of:
|
|
6
|
+
* nodemon → api-server-watch (chokidar + esbuild + forked child process)
|
|
7
|
+
*
|
|
8
|
+
* With:
|
|
9
|
+
* Vite SSR dev server (module graph + HMR) + Fastify (same process)
|
|
10
|
+
*
|
|
11
|
+
* When API source files change, Vite invalidates the affected modules and
|
|
12
|
+
* re-loads them on the next call – no process restart needed.
|
|
13
|
+
*/
|
|
14
|
+
export declare function startApiDevServer(port: number): Promise<{
|
|
15
|
+
viteServer: ViteDevServer;
|
|
16
|
+
close: () => Promise<void>;
|
|
17
|
+
}>;
|
|
18
|
+
//# sourceMappingURL=apiDevServer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiDevServer.d.ts","sourceRoot":"","sources":["../src/apiDevServer.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAc,aAAa,EAAE,MAAM,MAAM,CAAA;AAsLrD;;;;;;;;;;;GAWG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC7D,UAAU,EAAE,aAAa,CAAA;IACzB,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3B,CAAC,CAiCD"}
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import { glob } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
import fastifyUrlData from "@fastify/url-data";
|
|
5
|
+
import ansis from "ansis";
|
|
6
|
+
import fastify from "fastify";
|
|
7
|
+
import fastifyRawBody from "fastify-raw-body";
|
|
8
|
+
import { createServer as createViteServer, normalizePath } from "vite";
|
|
9
|
+
import { requestHandler } from "@cedarjs/api-server/requestHandlers";
|
|
10
|
+
import {
|
|
11
|
+
getApiSideBabelPlugins,
|
|
12
|
+
transformWithBabel
|
|
13
|
+
} from "@cedarjs/babel-config";
|
|
14
|
+
import { getAsyncStoreInstance } from "@cedarjs/context/dist/store";
|
|
15
|
+
import { createGraphQLYoga } from "@cedarjs/graphql-server";
|
|
16
|
+
import { getConfig, getPaths, projectSideIsEsm } from "@cedarjs/project-config";
|
|
17
|
+
import { getWorkspacePackageAliases } from "./lib/workspacePackageAliases.js";
|
|
18
|
+
const LAMBDA_FUNCTIONS = {};
|
|
19
|
+
let graphqlYoga = null;
|
|
20
|
+
let loadApiFunctionsInFlight = null;
|
|
21
|
+
let needsReloadAfterInFlight = false;
|
|
22
|
+
async function loadApiFunctions(viteServer) {
|
|
23
|
+
if (loadApiFunctionsInFlight) {
|
|
24
|
+
needsReloadAfterInFlight = true;
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
do {
|
|
28
|
+
needsReloadAfterInFlight = false;
|
|
29
|
+
loadApiFunctionsInFlight = internalLoadApiFunctions(viteServer);
|
|
30
|
+
try {
|
|
31
|
+
await loadApiFunctionsInFlight;
|
|
32
|
+
} finally {
|
|
33
|
+
loadApiFunctionsInFlight = null;
|
|
34
|
+
}
|
|
35
|
+
} while (needsReloadAfterInFlight);
|
|
36
|
+
}
|
|
37
|
+
async function internalLoadApiFunctions(viteServer) {
|
|
38
|
+
const cedarPaths = getPaths();
|
|
39
|
+
for (const key of Object.keys(LAMBDA_FUNCTIONS)) {
|
|
40
|
+
delete LAMBDA_FUNCTIONS[key];
|
|
41
|
+
}
|
|
42
|
+
let srcFunctions = [];
|
|
43
|
+
try {
|
|
44
|
+
srcFunctions = await Array.fromAsync(
|
|
45
|
+
glob("**/*.{ts,tsx,js,jsx}", {
|
|
46
|
+
cwd: cedarPaths.api.functions,
|
|
47
|
+
exclude: [
|
|
48
|
+
"**/*.test.{ts,tsx,js,jsx}",
|
|
49
|
+
"**/*.scenarios.{ts,tsx,js,jsx}",
|
|
50
|
+
"**/*.fixtures.{ts,tsx,js,jsx}",
|
|
51
|
+
"**/*.d.ts"
|
|
52
|
+
]
|
|
53
|
+
}),
|
|
54
|
+
(entry) => path.join(cedarPaths.api.functions, entry)
|
|
55
|
+
);
|
|
56
|
+
} catch {
|
|
57
|
+
srcFunctions = [];
|
|
58
|
+
}
|
|
59
|
+
const graphqlFunctionIndex = srcFunctions.findIndex(
|
|
60
|
+
(f) => path.basename(f).startsWith("graphql.")
|
|
61
|
+
);
|
|
62
|
+
if (graphqlFunctionIndex > 0) {
|
|
63
|
+
const [graphqlFn] = srcFunctions.splice(graphqlFunctionIndex, 1);
|
|
64
|
+
srcFunctions.unshift(graphqlFn);
|
|
65
|
+
}
|
|
66
|
+
console.log(ansis.dim.italic("Importing Server Functions... "));
|
|
67
|
+
const tsImport = Date.now();
|
|
68
|
+
let extractedGraphqlOptions = null;
|
|
69
|
+
const imports = srcFunctions.map(async (fnPath) => {
|
|
70
|
+
const ts = Date.now();
|
|
71
|
+
const routeName = path.basename(fnPath).replace(/\.(ts|tsx|js|jsx)$/, "");
|
|
72
|
+
try {
|
|
73
|
+
const mod = await viteServer.ssrLoadModule(pathToFileURL(fnPath).href);
|
|
74
|
+
const handler = (() => {
|
|
75
|
+
if ("handler" in mod) {
|
|
76
|
+
return mod.handler;
|
|
77
|
+
}
|
|
78
|
+
if ("default" in mod && mod.default && "handler" in mod.default) {
|
|
79
|
+
return mod.default.handler;
|
|
80
|
+
}
|
|
81
|
+
return void 0;
|
|
82
|
+
})();
|
|
83
|
+
if (handler) {
|
|
84
|
+
LAMBDA_FUNCTIONS[routeName] = handler;
|
|
85
|
+
console.log(
|
|
86
|
+
ansis.magenta("/" + routeName),
|
|
87
|
+
ansis.dim.italic(Date.now() - ts + " ms")
|
|
88
|
+
);
|
|
89
|
+
} else {
|
|
90
|
+
console.warn(
|
|
91
|
+
`[apiDevServer] No handler export found in function: ${fnPath}`
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
if (routeName === "graphql" && "__rw_graphqlOptions" in mod) {
|
|
95
|
+
extractedGraphqlOptions = mod.__rw_graphqlOptions;
|
|
96
|
+
}
|
|
97
|
+
} catch (err) {
|
|
98
|
+
viteServer.ssrFixStacktrace(err);
|
|
99
|
+
console.error(
|
|
100
|
+
`[apiDevServer] Failed to load function "${routeName}" from ${fnPath}:`,
|
|
101
|
+
err
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
await Promise.all(imports);
|
|
106
|
+
if (extractedGraphqlOptions) {
|
|
107
|
+
const { yoga } = await createGraphQLYoga(extractedGraphqlOptions);
|
|
108
|
+
graphqlYoga = yoga;
|
|
109
|
+
}
|
|
110
|
+
console.log(
|
|
111
|
+
ansis.dim.italic("...Done importing in " + (Date.now() - tsImport) + " ms")
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
function createFetchRequestFromFastify(req) {
|
|
115
|
+
const requestBody = req.method === "GET" || req.method === "HEAD" ? void 0 : typeof req.body === "string" ? req.body : req.body ? JSON.stringify(req.body) : void 0;
|
|
116
|
+
const href = `${req.protocol}://${req.host}${req.raw.url ?? "/"}`;
|
|
117
|
+
return new Request(href, {
|
|
118
|
+
method: req.method,
|
|
119
|
+
headers: req.headers,
|
|
120
|
+
body: requestBody
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
async function startApiDevServer(port) {
|
|
124
|
+
const cedarPaths = getPaths();
|
|
125
|
+
const cedarConfig = getConfig();
|
|
126
|
+
const apiPort = port || cedarConfig.api.port || 8911;
|
|
127
|
+
const apiHost = cedarConfig.api.host || "::";
|
|
128
|
+
const isEsm = projectSideIsEsm("api");
|
|
129
|
+
const normalizedBase = normalizePath(cedarPaths.base);
|
|
130
|
+
const normalizedApiSrc = normalizePath(cedarPaths.api.src);
|
|
131
|
+
const normalizedApiBase = normalizePath(cedarPaths.api.base);
|
|
132
|
+
const viteServer = await createViteDevServer(
|
|
133
|
+
cedarPaths,
|
|
134
|
+
cedarConfig,
|
|
135
|
+
isEsm,
|
|
136
|
+
normalizedBase
|
|
137
|
+
);
|
|
138
|
+
console.log(ansis.dim.italic("Starting API dev server..."));
|
|
139
|
+
await loadApiFunctions(viteServer);
|
|
140
|
+
setupHmrHandlers(viteServer, normalizedApiSrc, normalizedApiBase);
|
|
141
|
+
const app = await createFastifyApp(apiPort, apiHost);
|
|
142
|
+
const close = async () => {
|
|
143
|
+
await app.close();
|
|
144
|
+
await viteServer.close();
|
|
145
|
+
};
|
|
146
|
+
return { viteServer, close };
|
|
147
|
+
}
|
|
148
|
+
async function createViteDevServer(cedarPaths, cedarConfig, projectIsEsm, normalizedBase) {
|
|
149
|
+
const babelPlugins = getApiSideBabelPlugins({
|
|
150
|
+
openTelemetry: (cedarConfig.experimental?.opentelemetry?.enabled ?? false) && (cedarConfig.experimental?.opentelemetry?.wrapApi ?? false),
|
|
151
|
+
projectIsEsm
|
|
152
|
+
});
|
|
153
|
+
const workspacePkgSourceMap = Object.fromEntries(
|
|
154
|
+
Object.entries(getWorkspacePackageAliases(cedarPaths, cedarConfig)).map(
|
|
155
|
+
([name, sourceFile]) => [name, normalizePath(sourceFile)]
|
|
156
|
+
)
|
|
157
|
+
);
|
|
158
|
+
const viteServer = await createViteServer({
|
|
159
|
+
configFile: false,
|
|
160
|
+
root: cedarPaths.api.base,
|
|
161
|
+
appType: "custom",
|
|
162
|
+
clearScreen: false,
|
|
163
|
+
logLevel: "warn",
|
|
164
|
+
server: {
|
|
165
|
+
middlewareMode: true
|
|
166
|
+
},
|
|
167
|
+
resolve: {
|
|
168
|
+
// Map workspace package names directly to their TypeScript source entry
|
|
169
|
+
// files. This is processed by Vite's built-in alias plugin (enforce:
|
|
170
|
+
// 'pre') which runs before vite:resolve and correctly intercepts imports
|
|
171
|
+
// in the SSR module runner context.
|
|
172
|
+
alias: workspacePkgSourceMap
|
|
173
|
+
},
|
|
174
|
+
plugins: [
|
|
175
|
+
{
|
|
176
|
+
name: "cedar-api-babel-transform",
|
|
177
|
+
async transform(_code, id) {
|
|
178
|
+
if (!/\.(ts|tsx|js|jsx)$/.test(id)) {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
if (id.includes("node_modules")) {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
if (!id.startsWith(normalizedBase)) {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
try {
|
|
188
|
+
const result = await transformWithBabel(id, babelPlugins);
|
|
189
|
+
if (!result?.code) {
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
code: result.code,
|
|
194
|
+
map: result.map ?? null
|
|
195
|
+
};
|
|
196
|
+
} catch (err) {
|
|
197
|
+
this.warn(
|
|
198
|
+
`[cedar-api-babel-transform] Failed to transform ${id}: ${String(err)}`
|
|
199
|
+
);
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
]
|
|
205
|
+
});
|
|
206
|
+
return viteServer;
|
|
207
|
+
}
|
|
208
|
+
function invalidateApiModules(viteServer, normalizedApiSrc) {
|
|
209
|
+
const invalidated = /* @__PURE__ */ new Set();
|
|
210
|
+
const invalidateWithImporters = (mod) => {
|
|
211
|
+
if (!mod || invalidated.has(mod.id ?? mod.url)) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
invalidated.add(mod.id ?? mod.url);
|
|
215
|
+
viteServer.moduleGraph.invalidateModule(mod);
|
|
216
|
+
for (const importer of mod.importers) {
|
|
217
|
+
invalidateWithImporters(importer);
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
for (const mod of viteServer.moduleGraph.idToModuleMap.values()) {
|
|
221
|
+
if (mod.id?.startsWith(normalizedApiSrc)) {
|
|
222
|
+
invalidateWithImporters(mod);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
function setupHmrHandlers(viteServer, normalizedApiSrc, normalizedApiBase) {
|
|
227
|
+
viteServer.watcher.on("change", async (filePath) => {
|
|
228
|
+
const normalizedFilePath = normalizePath(filePath);
|
|
229
|
+
if (!normalizedFilePath.startsWith(normalizedApiSrc)) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
const displayPath = path.relative(normalizedApiBase, normalizedFilePath);
|
|
233
|
+
console.log(ansis.dim(`[change] ${displayPath}`));
|
|
234
|
+
const fileUrl = pathToFileURL(normalizedFilePath).href;
|
|
235
|
+
const mod = viteServer.moduleGraph.getModuleById(normalizedFilePath) ?? viteServer.moduleGraph.getModuleById(fileUrl);
|
|
236
|
+
if (mod) {
|
|
237
|
+
const invalidated = /* @__PURE__ */ new Set();
|
|
238
|
+
const invalidateWithImporters = (m) => {
|
|
239
|
+
if (!m || invalidated.has(m.id ?? m.url)) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
invalidated.add(m.id ?? m.url);
|
|
243
|
+
viteServer.moduleGraph.invalidateModule(m);
|
|
244
|
+
for (const importer of m.importers) {
|
|
245
|
+
invalidateWithImporters(importer);
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
invalidateWithImporters(mod);
|
|
249
|
+
}
|
|
250
|
+
await loadApiFunctions(viteServer);
|
|
251
|
+
});
|
|
252
|
+
viteServer.watcher.on("add", async (filePath) => {
|
|
253
|
+
const normalizedFilePath = normalizePath(filePath);
|
|
254
|
+
if (!normalizedFilePath.startsWith(normalizedApiSrc)) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
console.log(
|
|
258
|
+
ansis.dim(
|
|
259
|
+
`[add] ${path.relative(normalizedApiBase, normalizedFilePath)}`
|
|
260
|
+
)
|
|
261
|
+
);
|
|
262
|
+
invalidateApiModules(viteServer, normalizedApiSrc);
|
|
263
|
+
await loadApiFunctions(viteServer);
|
|
264
|
+
});
|
|
265
|
+
viteServer.watcher.on("unlink", async (filePath) => {
|
|
266
|
+
const normalizedFilePath = normalizePath(filePath);
|
|
267
|
+
if (!normalizedFilePath.startsWith(normalizedApiSrc)) {
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
console.log(
|
|
271
|
+
ansis.dim(
|
|
272
|
+
`[unlink] ${path.relative(normalizedApiBase, normalizedFilePath)}`
|
|
273
|
+
)
|
|
274
|
+
);
|
|
275
|
+
invalidateApiModules(viteServer, normalizedApiSrc);
|
|
276
|
+
await loadApiFunctions(viteServer);
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
async function createFastifyApp(apiPort, apiHost) {
|
|
280
|
+
const logLevel = process.env.NODE_ENV === "development" ? "debug" : "info";
|
|
281
|
+
const app = fastify({ logger: { level: logLevel } });
|
|
282
|
+
await app.register(fastifyRawBody);
|
|
283
|
+
app.register(fastifyUrlData);
|
|
284
|
+
app.addContentTypeParser(
|
|
285
|
+
["application/x-www-form-urlencoded", "multipart/form-data"],
|
|
286
|
+
{ parseAs: "string" },
|
|
287
|
+
app.defaultTextParser
|
|
288
|
+
);
|
|
289
|
+
const lambdaRequestHandler = async (req, reply) => {
|
|
290
|
+
const { routeName } = req.params;
|
|
291
|
+
const handler = LAMBDA_FUNCTIONS[routeName];
|
|
292
|
+
if (!handler) {
|
|
293
|
+
const errorMessage = `Function "${routeName}" was not found.`;
|
|
294
|
+
req.log.error(errorMessage);
|
|
295
|
+
reply.status(404);
|
|
296
|
+
reply.send({
|
|
297
|
+
error: errorMessage,
|
|
298
|
+
availableFunctions: Object.keys(LAMBDA_FUNCTIONS)
|
|
299
|
+
});
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
return requestHandler(req, reply, handler);
|
|
303
|
+
};
|
|
304
|
+
const graphqlHandler = async (req, reply) => {
|
|
305
|
+
if (!graphqlYoga) {
|
|
306
|
+
return reply.status(503).send({ error: "GraphQL Yoga instance not initialized" });
|
|
307
|
+
}
|
|
308
|
+
const request = createFetchRequestFromFastify(req);
|
|
309
|
+
const yoga = graphqlYoga;
|
|
310
|
+
const response = await getAsyncStoreInstance().run(/* @__PURE__ */ new Map(), async () => {
|
|
311
|
+
return yoga.handle(request, { req, reply });
|
|
312
|
+
});
|
|
313
|
+
return response;
|
|
314
|
+
};
|
|
315
|
+
app.all("/graphql", graphqlHandler);
|
|
316
|
+
app.all("/graphql/*", graphqlHandler);
|
|
317
|
+
app.all("/:routeName", lambdaRequestHandler);
|
|
318
|
+
app.all("/:routeName/*", lambdaRequestHandler);
|
|
319
|
+
app.addHook("onListen", (done) => {
|
|
320
|
+
const addr = app.server.address();
|
|
321
|
+
const listenPort = addr && typeof addr === "object" ? addr.port : apiPort;
|
|
322
|
+
console.log(
|
|
323
|
+
`API dev server listening at ${ansis.magenta(`http://localhost:${listenPort}/`)}`
|
|
324
|
+
);
|
|
325
|
+
console.log(
|
|
326
|
+
`GraphQL endpoint at ${ansis.magenta(`http://localhost:${listenPort}/graphql`)}`
|
|
327
|
+
);
|
|
328
|
+
done();
|
|
329
|
+
});
|
|
330
|
+
await app.listen({ port: apiPort, host: apiHost });
|
|
331
|
+
return app;
|
|
332
|
+
}
|
|
333
|
+
export {
|
|
334
|
+
startApiDevServer
|
|
335
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface BuildUDApiServerOptions {
|
|
2
|
+
verbose?: boolean;
|
|
3
|
+
apiRootPath?: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Builds the API server Universal Deploy Node entry using Vite.
|
|
7
|
+
*
|
|
8
|
+
* Runs a Vite server build that:
|
|
9
|
+
* 1. Installs `cedarUniversalDeployPlugin()` to register `virtual:cedar-api`
|
|
10
|
+
* and resolve `virtual:ud:catch-all` → Cedar's aggregate fetch dispatcher
|
|
11
|
+
* 2. Installs `node()` from `@universal-deploy/node/vite` to emit a
|
|
12
|
+
* self-contained Node server entry at `api/dist/ud/index.js`
|
|
13
|
+
*
|
|
14
|
+
* The emitted entry can be launched directly: node api/dist/ud/index.js
|
|
15
|
+
* That is what `cedar serve api` does.
|
|
16
|
+
*
|
|
17
|
+
* NOTE: The Vite "ssr" build target used here is a server-side module build
|
|
18
|
+
* concern — it is NOT related to Cedar HTML SSR or RSC. "ssr" simply means
|
|
19
|
+
* Vite produces a Node-compatible bundle rather than a browser bundle.
|
|
20
|
+
*/
|
|
21
|
+
export declare const buildUDApiServer: ({ verbose, apiRootPath, }?: BuildUDApiServerOptions) => Promise<void>;
|
|
22
|
+
//# sourceMappingURL=buildUDApiServer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildUDApiServer.d.ts","sourceRoot":"","sources":["../src/buildUDApiServer.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,uBAAuB;IACtC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,gBAAgB,GAAU,4BAGpC,uBAA4B,kBA+D9B,CAAA"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { getPaths } from "@cedarjs/project-config";
|
|
3
|
+
const buildUDApiServer = async ({
|
|
4
|
+
verbose = false,
|
|
5
|
+
apiRootPath
|
|
6
|
+
} = {}) => {
|
|
7
|
+
const { build } = await import("vite");
|
|
8
|
+
const { cedarUniversalDeployPlugin } = await import("./plugins/vite-plugin-cedar-universal-deploy.js");
|
|
9
|
+
const { node } = await import("@universal-deploy/node/vite");
|
|
10
|
+
const rwPaths = getPaths();
|
|
11
|
+
const outDir = path.join(rwPaths.api.dist, "ud");
|
|
12
|
+
await build({
|
|
13
|
+
// No configFile — we configure everything inline so this build is
|
|
14
|
+
// self-contained and does not require a vite.config.ts in api/.
|
|
15
|
+
configFile: false,
|
|
16
|
+
envFile: false,
|
|
17
|
+
logLevel: verbose ? "info" : "warn",
|
|
18
|
+
plugins: [
|
|
19
|
+
// Registers virtual:cedar-api with @universal-deploy/store and resolves
|
|
20
|
+
// virtual:ud:catch-all → virtual:cedar-api → Cedar's aggregate fetchable.
|
|
21
|
+
cedarUniversalDeployPlugin({ apiRootPath }),
|
|
22
|
+
// Emits a self-contained Node server entry (api/dist/ud/index.js) that
|
|
23
|
+
// imports virtual:ud:catch-all and starts an srvx HTTP server.
|
|
24
|
+
// This is a Vite server-build concern, not Cedar HTML SSR.
|
|
25
|
+
...node()
|
|
26
|
+
],
|
|
27
|
+
// The ssr environment is the Vite mechanism for server-side builds.
|
|
28
|
+
// Reminder: "ssr" here means "server-side module execution", NOT
|
|
29
|
+
// Cedar HTML SSR / streaming / RSC.
|
|
30
|
+
environments: {
|
|
31
|
+
ssr: {
|
|
32
|
+
build: {
|
|
33
|
+
outDir,
|
|
34
|
+
// Ensure @universal-deploy/node is bundled into the output so the
|
|
35
|
+
// emitted entry is self-contained.
|
|
36
|
+
rollupOptions: {
|
|
37
|
+
output: {
|
|
38
|
+
// Produce a single-file entry where possible; srvx chunks are
|
|
39
|
+
// split by the node() plugin automatically.
|
|
40
|
+
entryFileNames: "[name].js"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
resolve: {
|
|
45
|
+
// Do not externalise @universal-deploy/node — the node() plugin
|
|
46
|
+
// requires it to be bundled into the server entry.
|
|
47
|
+
noExternal: ["@universal-deploy/node"]
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
build: {
|
|
52
|
+
// This is a server (Node) build, not a browser build.
|
|
53
|
+
ssr: true
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
export {
|
|
58
|
+
buildUDApiServer
|
|
59
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cedar-unified-dev.d.ts","sourceRoot":"","sources":["../src/cedar-unified-dev.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createServer } from "vite";
|
|
3
|
+
import yargsParser from "yargs-parser";
|
|
4
|
+
import { getPaths, getConfig } from "@cedarjs/project-config";
|
|
5
|
+
import { startApiDevServer } from "./apiDevServer.js";
|
|
6
|
+
const startUnifiedDevServer = async () => {
|
|
7
|
+
const rwPaths = getPaths();
|
|
8
|
+
const cedarConfig = getConfig();
|
|
9
|
+
const configFile = rwPaths.web.viteConfig;
|
|
10
|
+
if (!configFile) {
|
|
11
|
+
throw new Error("Could not locate your web/vite.config.{js,ts} file");
|
|
12
|
+
}
|
|
13
|
+
const {
|
|
14
|
+
force: forceOptimize,
|
|
15
|
+
debug,
|
|
16
|
+
port: portArg,
|
|
17
|
+
apiPort: apiPortArg,
|
|
18
|
+
_: _positional,
|
|
19
|
+
...serverArgs
|
|
20
|
+
} = yargsParser(process.argv.slice(2), {
|
|
21
|
+
boolean: ["https", "open", "strictPort", "force", "cors", "debug"],
|
|
22
|
+
number: ["port", "apiPort"]
|
|
23
|
+
});
|
|
24
|
+
const webPort = portArg ?? cedarConfig.web.port ?? 8910;
|
|
25
|
+
const apiPort = apiPortArg ?? cedarConfig.api.port ?? 8911;
|
|
26
|
+
const { close: closeApi } = await startApiDevServer(apiPort);
|
|
27
|
+
const devServer = await createServer({
|
|
28
|
+
configFile,
|
|
29
|
+
// env file is handled by Cedar's plugins
|
|
30
|
+
envFile: false,
|
|
31
|
+
optimizeDeps: {
|
|
32
|
+
// This is the only value that isn't a server option
|
|
33
|
+
force: forceOptimize
|
|
34
|
+
},
|
|
35
|
+
server: {
|
|
36
|
+
port: webPort,
|
|
37
|
+
...serverArgs
|
|
38
|
+
},
|
|
39
|
+
logLevel: debug ? "info" : void 0
|
|
40
|
+
});
|
|
41
|
+
await devServer.listen();
|
|
42
|
+
process.stdin.on("data", async (data) => {
|
|
43
|
+
const str = data.toString().trim().toLowerCase();
|
|
44
|
+
if (str === "rs" || str === "restart") {
|
|
45
|
+
await devServer.restart(true);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
devServer.printUrls();
|
|
49
|
+
if (debug) {
|
|
50
|
+
console.log("~~~ Vite Server Config ~~~");
|
|
51
|
+
console.log(JSON.stringify(devServer.config, null, 2));
|
|
52
|
+
console.log("~~~~~~~~~~~~~~~~~~~~~~~~~~");
|
|
53
|
+
}
|
|
54
|
+
const shutdown = async () => {
|
|
55
|
+
await devServer.close();
|
|
56
|
+
await closeApi();
|
|
57
|
+
process.exit(0);
|
|
58
|
+
};
|
|
59
|
+
process.on("SIGINT", shutdown);
|
|
60
|
+
process.on("SIGTERM", shutdown);
|
|
61
|
+
};
|
|
62
|
+
startUnifiedDevServer().catch((err) => {
|
|
63
|
+
console.error("Failed to start unified dev server:", err);
|
|
64
|
+
process.exit(1);
|
|
65
|
+
});
|