@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.
Files changed (46) hide show
  1. package/dist/apiDevServer.d.ts +18 -0
  2. package/dist/apiDevServer.d.ts.map +1 -0
  3. package/dist/apiDevServer.js +335 -0
  4. package/dist/buildUDApiServer.d.ts +22 -0
  5. package/dist/buildUDApiServer.d.ts.map +1 -0
  6. package/dist/buildUDApiServer.js +59 -0
  7. package/dist/cedar-unified-dev.d.ts +3 -0
  8. package/dist/cedar-unified-dev.d.ts.map +1 -0
  9. package/dist/cedar-unified-dev.js +65 -0
  10. package/dist/cjs/apiDevServer.js +366 -0
  11. package/dist/cjs/buildUDApiServer.js +93 -0
  12. package/dist/cjs/cedar-unified-dev.js +88 -0
  13. package/dist/cjs/index.js +9 -0
  14. package/dist/cjs/lib/getMergedConfig.js +5 -0
  15. package/dist/cjs/lib/workspacePackageAliases.js +113 -0
  16. package/dist/cjs/plugins/vite-plugin-cedar-dev-dispatcher.js +223 -0
  17. package/dist/cjs/plugins/vite-plugin-cedar-universal-deploy.js +63 -0
  18. package/dist/cjs/rsc/rscBuildAnalyze.js +2 -0
  19. package/dist/cjs/rsc/rscBuildForServer.js +2 -0
  20. package/dist/cjs/rsc/rscBuildForSsr.js +2 -0
  21. package/dist/cjs/rsc/rscStudioHandlers.js +2 -1
  22. package/dist/index.d.ts +3 -0
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +6 -0
  25. package/dist/lib/getMergedConfig.d.ts.map +1 -1
  26. package/dist/lib/getMergedConfig.js +5 -0
  27. package/dist/lib/workspacePackageAliases.d.ts +18 -0
  28. package/dist/lib/workspacePackageAliases.d.ts.map +1 -0
  29. package/dist/lib/workspacePackageAliases.js +79 -0
  30. package/dist/plugins/vite-plugin-cedar-dev-dispatcher.d.ts +3 -0
  31. package/dist/plugins/vite-plugin-cedar-dev-dispatcher.d.ts.map +1 -0
  32. package/dist/plugins/vite-plugin-cedar-dev-dispatcher.js +189 -0
  33. package/dist/plugins/vite-plugin-cedar-universal-deploy.d.ts +6 -0
  34. package/dist/plugins/vite-plugin-cedar-universal-deploy.d.ts.map +1 -0
  35. package/dist/plugins/vite-plugin-cedar-universal-deploy.js +39 -0
  36. package/dist/rsc/rscBuildAnalyze.d.ts.map +1 -1
  37. package/dist/rsc/rscBuildAnalyze.js +2 -0
  38. package/dist/rsc/rscBuildForServer.d.ts.map +1 -1
  39. package/dist/rsc/rscBuildForServer.js +2 -0
  40. package/dist/rsc/rscBuildForSsr.d.ts.map +1 -1
  41. package/dist/rsc/rscBuildForSsr.js +2 -0
  42. package/dist/rsc/rscStudioHandlers.d.ts.map +1 -1
  43. package/dist/rsc/rscStudioHandlers.js +2 -1
  44. package/package.json +39 -19
  45. /package/bins/{rw-vite-build.mjs → cedar-vite-build.mjs} +0 -0
  46. /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,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cedar-unified-dev.d.ts.map
@@ -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
+ });