@ubean/build 0.1.2 → 0.1.3

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.
@@ -0,0 +1,611 @@
1
+ import { a as createRoutingVirtualModule, f as useVirtualRegistry, i as createPagesVirtualModule, n as createLocalesVirtualModule, r as createMetaVirtualModule, t as createAppVirtualModule } from "./virtual-modules-DXIaZdQI.js";
2
+ import { ubeanPlugin } from "./vite.js";
3
+ import { join, relative, resolve } from "pathe";
4
+ import { existsSync } from "node:fs";
5
+ import { cp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
6
+ import { build } from "vite";
7
+ import vue from "@vitejs/plugin-vue";
8
+ import { ubeanIslandsPlugin } from "@ubean/islands";
9
+ import { resolveModules } from "@ubean/modules";
10
+ import { findUserViteConfig } from "@ubean/utils";
11
+ import { VUE_PLUGIN_INCLUDE, createClientEntryVirtualModule, createServerEntryVirtualModule, createVueAppEntryVirtualModule, createVuePagesVirtualModule, ubeanVuePlugin } from "@ubean/vite";
12
+ import { consola } from "consola";
13
+ //#region src/production.ts
14
+ const logger = consola.withTag("ubean-build");
15
+ function getOutDirs(cwd, outputDir) {
16
+ const outputRoot = resolve(cwd, outputDir);
17
+ return {
18
+ root: outputRoot,
19
+ public: join(outputRoot, "public"),
20
+ server: join(outputRoot, "server"),
21
+ assets: join(outputRoot, "public", "assets"),
22
+ virtual: join(cwd, ".ubean", "virtual")
23
+ };
24
+ }
25
+ function toVitePath(p) {
26
+ return p.replace(/\\/g, "/");
27
+ }
28
+ async function generateVirtualModulesToDisk(cwd, config, scanResult, virtualDir) {
29
+ const mode = config.mode;
30
+ const ssrEnabled = mode === "fullstack" && config.ssr || mode === "ssg";
31
+ const hasPages = mode !== "backend";
32
+ const hasServer = mode !== "spa";
33
+ await mkdir(virtualDir, { recursive: true });
34
+ const registry = useVirtualRegistry();
35
+ registry.clear();
36
+ const viteSrcDir = toVitePath(relative(cwd, resolve(cwd, config.srcDir)));
37
+ const viteSrcPrefix = viteSrcDir ? `/${viteSrcDir}` : "";
38
+ registry.register(createRoutingVirtualModule(scanResult.apiRoutes.map((r) => ({
39
+ method: r.method?.toUpperCase() || "ALL",
40
+ path: r.route,
41
+ id: `${r.method}:${r.route}`,
42
+ filePath: r.fullPath
43
+ })), scanResult.middlewares.map((m) => ({
44
+ path: "/**",
45
+ filePath: m.fullPath,
46
+ order: m.order,
47
+ global: m.global
48
+ }))));
49
+ if (hasPages) {
50
+ registry.register(createPagesVirtualModule(scanResult.pages.map((p) => ({
51
+ name: p.name,
52
+ path: p.route,
53
+ filePath: p.fullPath,
54
+ layout: p.layout,
55
+ reuseTarget: p.reuseTarget
56
+ })), scanResult.layouts.map((l) => ({
57
+ name: l.name,
58
+ filePath: l.fullPath,
59
+ isDefault: l.isDefault
60
+ }))));
61
+ registry.register(createMetaVirtualModule());
62
+ registry.register(createVuePagesVirtualModule(scanResult.pages, scanResult.layouts));
63
+ registry.register(createVueAppEntryVirtualModule(scanResult.appEntry));
64
+ registry.register(createClientEntryVirtualModule());
65
+ }
66
+ registry.register(createAppVirtualModule(scanResult.apiRoutes, scanResult.middlewares, hasPages ? scanResult.pages : [], viteSrcPrefix || "/"));
67
+ registry.register(createLocalesVirtualModule(scanResult.locales, scanResult.defaultLocale, viteSrcPrefix || "/"));
68
+ if (hasServer) registry.register(createServerEntryVirtualModule(scanResult.serverEntry));
69
+ async function writeModule(id, filename, header = "// Auto-generated by ubean\n") {
70
+ const mod = registry.getModules().find((m) => m.id === id);
71
+ const content = mod ? await mod.load() : "";
72
+ await writeFile(join(virtualDir, filename), header + content, "utf-8");
73
+ }
74
+ await writeModule("ubean:routes", "routes.mjs");
75
+ await writeModule("ubean:app-config", "app-config.mjs");
76
+ await writeModule("ubean:locales", "locales.mjs");
77
+ if (hasPages) {
78
+ await writeModule("ubean:pages", "pages.ts");
79
+ await writeModule("ubean:meta", "meta.mjs");
80
+ await writeModule("virtual:ubean-pages", "vue-pages.ts", "");
81
+ await writeModule("virtual:ubean-app", "vue-app.ts", "");
82
+ await writeModule("virtual:ubean-client-entry", "client-entry.mjs", "");
83
+ }
84
+ if (hasServer) await writeModule("virtual:ubean-server", "server-entry.ts", "");
85
+ const pagesGlob = JSON.stringify(`${viteSrcPrefix}/pages/**/*.{vue,ts,tsx,js,jsx,md,mdx}`);
86
+ const routesGlob = JSON.stringify(`${viteSrcPrefix}/routes/**/*.{ts,js,mjs}`);
87
+ const middlewareGlob = JSON.stringify(`${viteSrcPrefix}/middleware/**/*.{ts,js,mjs}`);
88
+ const layoutsGlob = JSON.stringify(`${viteSrcPrefix}/layouts/**/*.{vue,ts}`);
89
+ const publicDir = toVitePath(resolve(cwd, config.build.outputDir || "dist", "public"));
90
+ const routesJson = JSON.stringify(scanResult.apiRoutes.map((r) => ({
91
+ relativePath: r.relativePath,
92
+ route: r.route,
93
+ method: r.method,
94
+ fileMeta: r.fileMeta
95
+ })));
96
+ const middlewareJson = JSON.stringify(scanResult.middlewares.map((m) => ({
97
+ relativePath: m.relativePath,
98
+ order: m.order,
99
+ global: m.global
100
+ })));
101
+ const pagesJson = JSON.stringify(scanResult.pages.map((p) => ({
102
+ relativePath: p.relativePath,
103
+ name: p.name,
104
+ route: p.route,
105
+ layout: p.layout,
106
+ reuseTarget: p.reuseTarget,
107
+ isReuse: p.isReuse,
108
+ pageMeta: p.pageMeta
109
+ })));
110
+ const layoutsJson = JSON.stringify(scanResult.layouts.map((l) => ({
111
+ name: l.name,
112
+ relativePath: l.relativePath,
113
+ isDefault: l.isDefault
114
+ })));
115
+ const rendererImport = ssrEnabled ? `import { createVueRenderer } from 'ubean/vue-ssr';` : "";
116
+ const rendererSetup = ssrEnabled ? `
117
+ // --- SSR renderer setup ---
118
+ const _defaultLayout = _layouts.find(l => l.isDefault)?.name || null;
119
+
120
+ const _rendererRoutes = _pages.map(p => {
121
+ // For reuse routes, load the target page's module (the .reuse.ts file
122
+ // only contains definePage metadata, not a Vue component).
123
+ const _targetPage = p.isReuse && p.reuseTarget ? _pages.find(tp => tp.name === p.reuseTarget) : undefined;
124
+ const _loaderKey = _targetPage?.relativePath || p.relativePath;
125
+ return {
126
+ path: p.route.replace(/\\*\\*:(\\w[\\w-]*)/g, ':$1(.*)*'),
127
+ name: p.name,
128
+ component: async () => {
129
+ const loader = pageLoaders[_loaderKey];
130
+ if (!loader) throw new Error('Page loader not found: ' + _loaderKey);
131
+ const mod = await loader();
132
+ return mod.default || mod;
133
+ },
134
+ meta: {
135
+ layout: p.layout === false ? false : p.layout || _defaultLayout,
136
+ pageName: p.name,
137
+ cache: p.cache === true ? true : undefined
138
+ }
139
+ };
140
+ });
141
+
142
+ const _layoutMap = new Map();
143
+ for (const l of _layouts) {
144
+ _layoutMap.set(l.name, l.relativePath);
145
+ }
146
+
147
+ const _pageRenderer = createVueRenderer({
148
+ routes: _rendererRoutes,
149
+ async resolveLayoutComponent(name) {
150
+ if (name === false || name == null) return null;
151
+ const relPath = _layoutMap.get(name);
152
+ if (!relPath) return null;
153
+ const loader = layoutLoaders[relPath];
154
+ if (!loader) return null;
155
+ const mod = await loader();
156
+ return mod.default || mod;
157
+ },
158
+ defaultLayout: _defaultLayout,
159
+ resolveAppConfig: () => _resolveAppConfig('server')
160
+ });
161
+ ` : `
162
+ // --- SSR disabled (mode=${mode}, ssr=${config.ssr}) ---
163
+ // pageRenderer is null; page requests fall back to a client-only HTML shell.
164
+ const _pageRenderer = null;`;
165
+ if (hasServer) {
166
+ const serverEntry = `// Auto-generated server entry
167
+ import { createUbeanApp, applyServerConfig } from 'ubean/runtime/app';
168
+ ${rendererImport}
169
+ import { resolveAppConfig as _resolveAppConfig } from 'virtual:ubean-app';
170
+ import { resolveServerConfig as _resolveServerConfig } from 'virtual:ubean-server';
171
+ import { loadLocales } from 'ubean:locales';
172
+ import { readFileSync } from 'node:fs';
173
+ import { join, dirname } from 'node:path';
174
+ import { fileURLToPath } from 'node:url';
175
+
176
+ export { createUbeanApp };
177
+
178
+ const routeModules = import.meta.glob(${routesGlob}, { eager: false });
179
+ const middlewareModules = import.meta.glob(${middlewareGlob}, { eager: false });
180
+ const pageModules = import.meta.glob(${pagesGlob}, { eager: false });
181
+ const layoutModules = import.meta.glob(${layoutsGlob}, { eager: false });
182
+
183
+ const _srcPrefix = ${JSON.stringify(viteSrcPrefix)};
184
+ function normalizeKey(p) {
185
+ const prefixes = ['/routes/', '/middleware/', '/pages/', '/layouts/'];
186
+ for (const prefix of prefixes) {
187
+ const fullPrefix = _srcPrefix + prefix;
188
+ if (p.includes(fullPrefix)) {
189
+ const idx = p.indexOf(fullPrefix);
190
+ return p.slice(idx + fullPrefix.length);
191
+ }
192
+ }
193
+ return p;
194
+ }
195
+
196
+ export const routeLoaders = {};
197
+ for (const [key, loader] of Object.entries(routeModules)) {
198
+ routeLoaders[normalizeKey(key)] = loader;
199
+ }
200
+
201
+ export const middlewareLoaders = {};
202
+ for (const [key, loader] of Object.entries(middlewareModules)) {
203
+ middlewareLoaders[normalizeKey(key)] = loader;
204
+ }
205
+
206
+ export const pageLoaders = {};
207
+ for (const [key, loader] of Object.entries(pageModules)) {
208
+ pageLoaders[normalizeKey(key)] = loader;
209
+ }
210
+
211
+ const layoutLoaders = {};
212
+ for (const [key, loader] of Object.entries(layoutModules)) {
213
+ layoutLoaders[normalizeKey(key)] = loader;
214
+ }
215
+
216
+ const _routes = ${routesJson};
217
+ const _middleware = ${middlewareJson};
218
+ const _pages = ${pagesJson};
219
+ const _layouts = ${layoutsJson};
220
+ ${rendererSetup}
221
+ // --- Client asset tags from Vite manifest ---
222
+ const __dirname = dirname(fileURLToPath(import.meta.url));
223
+ let _assetTags = { css: '', preloads: '', body: '' };
224
+ try {
225
+ const manifestPath = join(__dirname, '..', 'public', '.vite', 'manifest.json');
226
+ const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8'));
227
+ const entry = Object.values(manifest).find(m => m.isEntry);
228
+ if (entry) {
229
+ _assetTags.body = '<script type="module" src="/' + entry.file + '"><\/script>';
230
+ if (Array.isArray(entry.css)) {
231
+ _assetTags.css = entry.css.map(c => '<link rel="stylesheet" href="/' + c + '">').join('\\n');
232
+ }
233
+ }
234
+ } catch (e) {
235
+ console.warn('[ubean] Failed to load client manifest:', e.message || e);
236
+ }
237
+
238
+ export async function createApp(options = {}) {
239
+ const app = createUbeanApp({
240
+ rootDir: ${JSON.stringify(cwd)},
241
+ routes: _routes,
242
+ middleware: _middleware,
243
+ pages: _pages,
244
+ layouts: _layouts,
245
+ routeLoaders,
246
+ middlewareLoaders,
247
+ pageLoaders,
248
+ pageRenderer: _pageRenderer,
249
+ pageAssetTags: _assetTags,
250
+ publicDir: ${JSON.stringify(publicDir)},
251
+ i18nConfig: ${JSON.stringify(config.i18n)},
252
+ ...options
253
+ });
254
+
255
+ // Apply user's defineServer config (plugins, hooks, onAppCreate) before init
256
+ const _serverConfig = _resolveServerConfig('prod');
257
+ await applyServerConfig(app, _serverConfig);
258
+
259
+ await loadLocales();
260
+ await app.init();
261
+
262
+ // Call onServerReady after init completes
263
+ if (_serverConfig.onServerReady) {
264
+ await _serverConfig.onServerReady(app);
265
+ }
266
+
267
+ return app;
268
+ }
269
+
270
+ export default async function createFetchHandler() {
271
+ const app = await createApp();
272
+ return app.fetch;
273
+ }
274
+
275
+ export const handler = async (req, ctx) => {
276
+ const app = await createApp();
277
+ return app.fetch(req, ctx);
278
+ };
279
+ `;
280
+ await writeFile(join(virtualDir, "server-entry.mjs"), serverEntry, "utf-8");
281
+ }
282
+ return virtualDir;
283
+ }
284
+ function getPresetBuildConfig(preset) {
285
+ switch (preset.name) {
286
+ case "node":
287
+ case "bun":
288
+ case "deno": return {
289
+ format: "esm",
290
+ target: "node18",
291
+ entryType: "node",
292
+ external: [
293
+ "hono",
294
+ "vue",
295
+ "vue/server-renderer",
296
+ /^ubean(\/.*)?$/,
297
+ /^node:/
298
+ ]
299
+ };
300
+ case "cloudflare": return {
301
+ format: "esm",
302
+ target: "es2022",
303
+ entryType: "worker",
304
+ external: [
305
+ "hono",
306
+ "vue",
307
+ "vue/server-renderer",
308
+ /^ubean(\/.*)?$/
309
+ ]
310
+ };
311
+ default: return {
312
+ format: "esm",
313
+ target: "es2022",
314
+ entryType: "fetch",
315
+ external: [
316
+ "hono",
317
+ "vue",
318
+ "vue/server-renderer",
319
+ /^ubean(\/.*)?$/
320
+ ]
321
+ };
322
+ }
323
+ }
324
+ function generateNodeServerEntry() {
325
+ return `// Auto-generated ubean Node.js server entry
326
+ import { createServer } from 'node:http';
327
+ import createFetchHandler from './entry.mjs';
328
+
329
+ const port = Number(process.env.PORT || 9527);
330
+ const host = process.env.HOST || '0.0.0.0';
331
+
332
+ async function main() {
333
+ const fetch = await createFetchHandler();
334
+
335
+ const server = createServer(async (req, res) => {
336
+ try {
337
+ const protocol = req.socket?.encrypted ? 'https' : 'http';
338
+ const url = \`\${protocol}://\${req.headers.host || host}\${req.url || '/'}\`;
339
+ const headers = new Headers();
340
+ for (const [key, value] of Object.entries(req.headers)) {
341
+ if (value) {
342
+ if (Array.isArray(value)) {
343
+ for (const v of value) headers.append(key, v);
344
+ } else {
345
+ headers.set(key, value);
346
+ }
347
+ }
348
+ }
349
+ const method = req.method || 'GET';
350
+ const body = method === 'GET' || method === 'HEAD' ? undefined : req;
351
+ const webReq = new Request(url, { method, headers, body, duplex: 'half' });
352
+ const webRes = await fetch(webReq);
353
+
354
+ res.statusCode = webRes.status;
355
+ res.statusMessage = webRes.statusText;
356
+ webRes.headers.forEach((value, key) => res.setHeader(key, value));
357
+
358
+ if (webRes.body) {
359
+ const reader = webRes.body.getReader();
360
+ try {
361
+ while (true) {
362
+ const { done, value: chunk } = await reader.read();
363
+ if (done) break;
364
+ res.write(chunk);
365
+ }
366
+ } finally {
367
+ reader.releaseLock();
368
+ }
369
+ }
370
+ res.end();
371
+ } catch (err) {
372
+ if (!res.headersSent) {
373
+ res.statusCode = 500;
374
+ res.setHeader('Content-Type', 'text/plain');
375
+ }
376
+ res.end(err instanceof Error ? err.message : String(err));
377
+ }
378
+ });
379
+
380
+ server.listen(port, host, () => {
381
+ console.log(\`ubean server listening on http://\${host}:\${port}\`);
382
+ });
383
+
384
+ const shutdown = () => {
385
+ server.close(() => process.exit(0));
386
+ };
387
+ process.on('SIGINT', shutdown);
388
+ process.on('SIGTERM', shutdown);
389
+ }
390
+
391
+ main();
392
+ `.trim();
393
+ }
394
+ function generateStandardHandlerEntry() {
395
+ return `// Auto-generated ubean standard fetch handler
396
+ import createFetchHandler from './entry.mjs';
397
+
398
+ const handlerPromise = createFetchHandler();
399
+ export default async function fetch(req, ctx) {
400
+ const handler = await handlerPromise;
401
+ return handler(req, ctx);
402
+ }
403
+ `.trim();
404
+ }
405
+ function generateCloudflareWorkerEntry() {
406
+ return `// Auto-generated ubean Cloudflare Worker entry
407
+ import createFetchHandler from './entry.mjs';
408
+
409
+ const handlerPromise = createFetchHandler();
410
+ export default {
411
+ async fetch(req, env, ctx) {
412
+ const handler = await handlerPromise;
413
+ return handler(req, { ...ctx, env });
414
+ }
415
+ };
416
+ `.trim();
417
+ }
418
+ async function buildProduction(options) {
419
+ const { cwd, config, preset, scanResult, minify = true, sourcemap = false } = options;
420
+ const outDirs = getOutDirs(cwd, config.build.outputDir);
421
+ const srcDir = resolve(cwd, config.srcDir);
422
+ const mode = config.mode;
423
+ const ssrEnabled = mode === "fullstack" && config.ssr || mode === "ssg";
424
+ const hasPages = mode !== "backend";
425
+ const hasServer = mode !== "spa";
426
+ logger.info(`Cleaning output directory... (mode=${mode}${mode === "fullstack" ? `, ssr=${config.ssr}` : ""})`);
427
+ if (existsSync(outDirs.root)) await rm(outDirs.root, {
428
+ recursive: true,
429
+ force: true
430
+ });
431
+ if (hasPages) await mkdir(outDirs.public, { recursive: true });
432
+ if (hasServer) await mkdir(outDirs.server, { recursive: true });
433
+ logger.info("Generating virtual modules...");
434
+ await generateVirtualModulesToDisk(cwd, config, scanResult, outDirs.virtual);
435
+ const userViteConfig = findUserViteConfig(cwd);
436
+ const builtinPlugins = [];
437
+ if (hasPages) builtinPlugins.push(vue({
438
+ include: VUE_PLUGIN_INCLUDE,
439
+ template: { compilerOptions: { isCustomElement: (tag) => tag.startsWith("ubean-") } }
440
+ }));
441
+ if (!userViteConfig) {
442
+ builtinPlugins.push(ubeanPlugin({ config }));
443
+ if (hasPages) builtinPlugins.push(...ubeanVuePlugin({ config }), ubeanIslandsPlugin());
444
+ }
445
+ const { plugins } = await resolveModules({
446
+ cwd,
447
+ config,
448
+ builtinPlugins
449
+ });
450
+ const presetBuildConfig = getPresetBuildConfig(preset);
451
+ const virtualDir = outDirs.virtual;
452
+ const commonResolve = { alias: {
453
+ "virtual:ubean-pages": join(virtualDir, "vue-pages.ts"),
454
+ "virtual:ubean-app": join(virtualDir, "vue-app.ts"),
455
+ "virtual:ubean-server": join(virtualDir, "server-entry.ts"),
456
+ "virtual:ubean-client-entry": join(virtualDir, "client-entry.mjs"),
457
+ "#ubean-pages": join(virtualDir, "vue-pages.ts"),
458
+ "#ubean-app": join(virtualDir, "vue-app.ts"),
459
+ "#ubean-server": join(virtualDir, "server-entry.ts"),
460
+ "#ubean-client-entry": join(virtualDir, "client-entry.mjs"),
461
+ "ubean:pages": join(virtualDir, "pages.ts"),
462
+ "ubean:routes": join(virtualDir, "routes.mjs"),
463
+ "ubean:app-config": join(virtualDir, "app-config.mjs"),
464
+ "ubean:locales": join(virtualDir, "locales.mjs"),
465
+ "ubean:meta": join(virtualDir, "meta.mjs")
466
+ } };
467
+ let clientManifest = {};
468
+ if (hasPages) {
469
+ logger.info("Building client bundle...");
470
+ const clientEntryPath = join(srcDir, "entry.client.ts");
471
+ const clientInput = existsSync(clientEntryPath) ? clientEntryPath : join(virtualDir, "client-entry.mjs");
472
+ await writeFile(join(virtualDir, "index.html"), `<!DOCTYPE html>
473
+ <html>
474
+ <head>
475
+ <meta charset="UTF-8" />
476
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
477
+ <link rel="icon" href="/favicon.svg" type="image/svg+xml" />
478
+ <title>Ubean App</title>
479
+ </head>
480
+ <body>
481
+ <div id="app"></div>
482
+ <script type="module" src="virtual:ubean-client-entry"><\/script>
483
+ </body>
484
+ </html>`, "utf-8");
485
+ await build({
486
+ root: cwd,
487
+ configFile: userViteConfig ?? false,
488
+ mode: "production",
489
+ build: {
490
+ outDir: outDirs.public,
491
+ assetsDir: "assets",
492
+ minify: minify ? "oxc" : false,
493
+ sourcemap,
494
+ manifest: true,
495
+ ssrManifest: true,
496
+ rollupOptions: {
497
+ input: { app: clientInput },
498
+ output: {
499
+ entryFileNames: "assets/[name]-[hash].js",
500
+ chunkFileNames: "assets/chunks/[name]-[hash].js",
501
+ assetFileNames: "assets/[name]-[hash].[ext]"
502
+ }
503
+ },
504
+ emptyOutDir: false
505
+ },
506
+ plugins: [...plugins],
507
+ resolve: commonResolve,
508
+ optimizeDeps: { exclude: [
509
+ "ubean",
510
+ "virtual:ubean-pages",
511
+ "virtual:ubean-app",
512
+ "virtual:ubean-server",
513
+ "virtual:ubean-client-entry",
514
+ "#ubean-pages",
515
+ "#ubean-app",
516
+ "#ubean-server",
517
+ "#ubean-client-entry"
518
+ ] }
519
+ });
520
+ const manifestPath = join(outDirs.public, ".vite", "manifest.json");
521
+ if (existsSync(manifestPath)) try {
522
+ clientManifest = JSON.parse(await readFile(manifestPath, "utf-8"));
523
+ } catch {}
524
+ const publicDir = join(cwd, "public");
525
+ if (existsSync(publicDir)) {
526
+ logger.info("Copying public assets...");
527
+ await cp(publicDir, outDirs.public, { recursive: true });
528
+ }
529
+ }
530
+ let serverEntry = "";
531
+ if (hasServer) {
532
+ logger.info(ssrEnabled ? "Building SSR bundle..." : "Building server bundle (SSR disabled)...");
533
+ const serverEntryPath = join(virtualDir, "server-entry.mjs");
534
+ await build({
535
+ root: cwd,
536
+ configFile: userViteConfig ?? false,
537
+ mode: "production",
538
+ ssr: {
539
+ target: presetBuildConfig.target === "node18" ? "node" : "webworker",
540
+ noExternal: ["ubean"]
541
+ },
542
+ build: {
543
+ outDir: outDirs.server,
544
+ ssr: true,
545
+ minify: false,
546
+ sourcemap,
547
+ rollupOptions: {
548
+ input: serverEntryPath,
549
+ external: presetBuildConfig.external,
550
+ output: {
551
+ format: presetBuildConfig.format,
552
+ entryFileNames: "entry.mjs",
553
+ chunkFileNames: "chunks/[name]-[hash].mjs",
554
+ inlineDynamicImports: presetBuildConfig.entryType === "worker"
555
+ }
556
+ },
557
+ emptyOutDir: false
558
+ },
559
+ plugins: [...plugins],
560
+ resolve: commonResolve
561
+ });
562
+ serverEntry = "entry.mjs";
563
+ if (presetBuildConfig.entryType === "node") {
564
+ await writeFile(join(outDirs.server, "server.mjs"), generateNodeServerEntry(), "utf-8");
565
+ serverEntry = "server.mjs";
566
+ await writeFile(join(outDirs.server, "package.json"), JSON.stringify({
567
+ type: "module",
568
+ private: true,
569
+ main: "./server.mjs",
570
+ dependencies: { hono: "^4.0.0" }
571
+ }, null, 2), "utf-8");
572
+ } else if (presetBuildConfig.entryType === "worker") {
573
+ await writeFile(join(outDirs.server, "worker.mjs"), generateCloudflareWorkerEntry(), "utf-8");
574
+ serverEntry = "worker.mjs";
575
+ const wranglerToml = `
576
+ name = "ubean-app"
577
+ main = "./server/worker.mjs"
578
+ compatibility_date = "2024-01-01"
579
+ assets = { directory = "./public" }
580
+ `.trim();
581
+ await writeFile(join(outDirs.root, "wrangler.toml"), wranglerToml, "utf-8");
582
+ } else {
583
+ await writeFile(join(outDirs.server, "handler.mjs"), generateStandardHandlerEntry(), "utf-8");
584
+ serverEntry = "handler.mjs";
585
+ }
586
+ }
587
+ const assets = [];
588
+ for (const [key, entry] of Object.entries(clientManifest)) assets.push({
589
+ file: entry.file,
590
+ src: key,
591
+ isEntry: entry.isEntry,
592
+ css: entry.css
593
+ });
594
+ const manifest = {
595
+ assets,
596
+ entry: serverEntry,
597
+ clientDir: hasPages ? relative(cwd, outDirs.public) : "",
598
+ serverDir: hasServer ? relative(cwd, outDirs.server) : "",
599
+ preset: preset.name || "standard"
600
+ };
601
+ await writeFile(join(outDirs.root, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
602
+ logger.success(`Build complete! Output: ${outDirs.root}`);
603
+ if (hasPages) logger.info(` Client assets: ${outDirs.public}`);
604
+ if (hasServer) {
605
+ logger.info(` Server bundle: ${outDirs.server}`);
606
+ logger.info(` Entry: ${serverEntry}`);
607
+ }
608
+ return manifest;
609
+ }
610
+ //#endregion
611
+ export { buildProduction };