@ubean/build 0.6.0-beta.1 → 0.6.0-beta.2

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.
@@ -99,6 +99,8 @@ interface AutoImportResult {
99
99
  components: ComponentInfo[];
100
100
  autoImportsDtsPath: string;
101
101
  componentsDtsPath: string;
102
+ /** 虚拟组件(配对/单边基名)的 ambient 声明文件。没有虚拟组件时内容为空声明。 */
103
+ virtualComponentsDtsPath: string;
102
104
  }
103
105
  export declare function generateAutoImports(_scanResult: ScanResult, options: GenerateAutoImportsOptions): Promise<AutoImportResult>;
104
106
  export declare function getBuiltinComposables(): Import[];
@@ -228,6 +230,7 @@ export interface CodegenResult {
228
230
  i18nTypesPath?: string | null;
229
231
  autoImportsDtsPath?: string;
230
232
  componentsDtsPath?: string;
233
+ virtualComponentsDtsPath?: string;
231
234
  generated: string[];
232
235
  }
233
236
  export declare function generateTypes(result: ScanResult, options: CodegenOptions): Promise<CodegenResult>;
@@ -1,2 +1,2 @@
1
- import { C as getUbeanComponentsConfig, E as toArray, S as getUbeanAutoImportConfig, T as resolveComponentsConfig, _ as VUE_ROUTER_PRESET, a as generateOpenApiTypesFromServer, b as getAutoImportPresets, c as generateI18nTypes, d as HONO_OPENAPI_PRESET, f as UBEAN_CLIENT_PRESET, g as VUE_PRESET, h as VUE_MACROS_PRESET, i as generateOpenApiTypes, l as messagesToTsType, m as VUE_I18N_PRESET, n as CODEGEN_FILES, o as generatePageTypes, p as UBEAN_SERVER_PRESET, r as generateTypes, s as generateRouteTypes, t as CODEGEN_CONTRACT_VERSION, u as BUILTIN_PRESETS, v as generateAutoImports, w as resolveAutoImportsConfig, x as getBuiltinComposables, y as generateImportsTransform } from "../codegen-B3oGeRtK.js";
1
+ import { C as getUbeanAutoImportConfig, D as toArray, E as resolveComponentsConfig, S as getBuiltinComposables, T as resolveAutoImportsConfig, _ as VUE_PRESET, a as generateOpenApiTypesFromServer, b as generateImportsTransform, c as generateI18nTypes, f as HONO_OPENAPI_PRESET, g as VUE_MACROS_PRESET, h as VUE_I18N_PRESET, i as generateOpenApiTypes, l as messagesToTsType, m as UBEAN_SERVER_PRESET, n as CODEGEN_FILES, o as generatePageTypes, p as UBEAN_CLIENT_PRESET, r as generateTypes, s as generateRouteTypes, t as CODEGEN_CONTRACT_VERSION, u as BUILTIN_PRESETS, v as VUE_ROUTER_PRESET, w as getUbeanComponentsConfig, x as getAutoImportPresets, y as generateAutoImports } from "../codegen-Up8-XhRo.js";
2
2
  export { BUILTIN_PRESETS, CODEGEN_CONTRACT_VERSION, CODEGEN_FILES, HONO_OPENAPI_PRESET, UBEAN_CLIENT_PRESET, UBEAN_SERVER_PRESET, VUE_I18N_PRESET, VUE_MACROS_PRESET, VUE_PRESET, VUE_ROUTER_PRESET, generateAutoImports, generateI18nTypes, generateImportsTransform, generateOpenApiTypes, generateOpenApiTypesFromServer, generatePageTypes, generateRouteTypes, generateTypes, getAutoImportPresets, getBuiltinComposables, getUbeanAutoImportConfig, getUbeanComponentsConfig, messagesToTsType, resolveAutoImportsConfig, resolveComponentsConfig, toArray };
@@ -260,23 +260,55 @@ function transformImportPath(filePath, srcDir) {
260
260
  function isPackageSource(from) {
261
261
  return !from.startsWith(".") && !from.startsWith("/") && !from.startsWith("~");
262
262
  }
263
+ /**
264
+ * `.server.vue` / `.client.vue` 不是独立组件,**不能**进自动导入表。
265
+ *
266
+ * 它们是同一个组件的两个变体:`.client.vue` 客户端独有、`.server.vue` 服务端独有,
267
+ * 成对出现时(`Foo.server.vue` + `Foo.client.vue`)由 `@ubean/islands` 的
268
+ * `resolveId` 按基名 `Foo.vue` 生成配对包装。用户侧的用法是**显式 import**
269
+ * (`import Foo from './Foo.vue'` 或直接 import 某一半),不存在 `<Foo.server />` 这种写法。
270
+ *
271
+ * 而按文件名派生名字会把它们扫成 `Foo.server` / `Foo.client` —— 这些名字进了
272
+ * `components.d.ts` 就是**非法 TypeScript**:ubean 自己的写入器会产出未加引号的
273
+ * 带点键(接口成员不允许限定名,`@ts-nocheck` 也压不住语法错误),
274
+ * unplugin-vue-components 重写时会产出 `const 'Foo.server': …`(`declare global` 块里
275
+ * 非法)—— 结果示例项目的 `pnpm type-check` 直接红。
276
+ *
277
+ * codegen 侧在 `scanComponentsDir` 里按这个形态分区(半成品不进组件表,但会被收成虚拟组件);
278
+ * unplugin 没有分区逻辑,所以这份 glob 直接喂给它的 `globsExclude`(`./vue-plugin.ts`),
279
+ * 保证两个写入器都不产出这些条目。
280
+ */
281
+ const COMPONENT_HALF_GLOBS = ["**/*.server.vue", "**/*.client.vue"];
263
282
  async function scanComponentsDir(dir, srcDir, directoryAsNamespace, ignore = [
264
283
  "**/*.test.*",
265
284
  "**/*.spec.*",
266
285
  "**/_*"
267
286
  ]) {
268
287
  const components = [];
288
+ const virtualComponents = [];
269
289
  const files = await glob("**/*.vue", {
270
290
  cwd: dir,
271
291
  dot: true,
272
292
  ignore,
273
293
  absolute: true
274
294
  }).catch(() => []);
295
+ /** 基名 → 半成品真实路径(`/foo/Base.server.vue` 等)。 */
296
+ const halves = /* @__PURE__ */ new Map();
297
+ /** 同目录下真实存在的 `.vue` 基名 —— 它们由 TS 自行解析,不需要 ambient 声明。 */
298
+ const realBases = /* @__PURE__ */ new Set();
275
299
  for (const fullPath of files.sort()) {
276
300
  const relativeToSrc = toPosixPath(relative(srcDir, fullPath));
277
301
  const relativeToDir = toPosixPath(relative(dir, fullPath));
278
302
  const base = fileBasename(fullPath);
279
303
  if (base.startsWith("_")) continue;
304
+ const half = /^(.*)\.(server|client)$/.exec(base);
305
+ if (half) {
306
+ const entry = halves.get(half[1]) ?? {};
307
+ entry[half[2]] = fullPath;
308
+ halves.set(half[1], entry);
309
+ continue;
310
+ }
311
+ realBases.add(base);
280
312
  let name;
281
313
  if (directoryAsNamespace) {
282
314
  const dirPart = fileDirname(relativeToDir) === "." ? "" : fileDirname(relativeToDir);
@@ -291,7 +323,18 @@ async function scanComponentsDir(dir, srcDir, directoryAsNamespace, ignore = [
291
323
  pascalName: name
292
324
  });
293
325
  }
294
- return components;
326
+ for (const [baseName, pair] of halves) {
327
+ if (realBases.has(baseName)) continue;
328
+ virtualComponents.push({
329
+ baseName,
330
+ name: toPascalCase(baseName),
331
+ typeSourcePath: pair.server ?? pair.client
332
+ });
333
+ }
334
+ return {
335
+ components,
336
+ virtualComponents
337
+ };
295
338
  }
296
339
  async function generateAutoImports(_scanResult, options) {
297
340
  const { cwd, srcDir, buildDir, dirs = {}, autoImports: autoImportsInput, components: componentsInput } = options;
@@ -304,6 +347,7 @@ async function generateAutoImports(_scanResult, options) {
304
347
  const componentsDir = dirs.components || "components";
305
348
  let composablesImports = [];
306
349
  let components = [];
350
+ const virtualComponents = [];
307
351
  const autoImportsDtsPath = join(outDir, "auto-imports.d.ts");
308
352
  const componentsDtsPath = join(outDir, "components.d.ts");
309
353
  if (resolvedAutoImports.enabled) {
@@ -330,29 +374,86 @@ async function generateAutoImports(_scanResult, options) {
330
374
  from: transformImportPath(imp.from, srcDir)
331
375
  };
332
376
  });
333
- const dtsContent = toTypeDeclarationFile(composablesImports, { resolvePath: (imp) => {
334
- if (isPackageSource(imp.from)) return imp.from;
335
- return transformImportPath(imp.from, srcDir);
336
- } });
337
- await writeFile(autoImportsDtsPath, dtsContent, "utf-8");
377
+ const resolveFrom = (from) => isPackageSource(from) ? from : transformImportPath(from, srcDir);
378
+ const dtsContent = toTypeDeclarationFile(composablesImports, { resolvePath: (imp) => resolveFrom(imp.from) });
379
+ await writeFile(autoImportsDtsPath, `${dtsContent}\n\n${buildTemplateAutoImportBlock(composablesImports, resolveFrom)}`, "utf-8");
338
380
  } else await writeFile(autoImportsDtsPath, "// Auto-generated by ubean - auto-imports disabled\n/* eslint-disable */\n// @ts-nocheck\nexport {}\n", "utf-8");
339
381
  if (resolvedComponents.enabled) {
340
382
  const allComponentsDirs = [join(srcDir, componentsDir), ...resolvedComponents.options.dirs ?? []];
341
383
  for (const dir of allComponentsDirs) {
342
384
  const scanned = await scanComponentsDir(dir, srcDir, directoryAsNamespace);
343
- components.push(...scanned);
385
+ components.push(...scanned.components);
386
+ virtualComponents.push(...scanned.virtualComponents);
344
387
  }
345
388
  }
346
389
  const componentsDts = generateComponentsDts(components, componentsDtsPath);
347
390
  await writeFile(componentsDtsPath, componentsDts, "utf-8");
391
+ const virtualComponentsDtsPath = join(outDir, "virtual-components.d.ts");
392
+ await writeFile(virtualComponentsDtsPath, generateVirtualComponentsDts(virtualComponents, virtualComponentsDtsPath), "utf-8");
348
393
  return {
349
394
  composablesImports,
350
395
  components,
351
396
  autoImportsDtsPath,
352
- componentsDtsPath
397
+ componentsDtsPath,
398
+ virtualComponentsDtsPath
353
399
  };
354
400
  }
355
401
  /**
402
+ * 生成「模板里的自动导入」声明段(对齐 `AutoImport({ vueTemplate: true })` 的产物)。
403
+ *
404
+ * **为什么必须自己产出这段**:模板表达式里的标识符由 vue 的**组件实例类型**解析
405
+ * (vue-tsc 把模板编译成 `__VLS_ctx.x`,即 `ComponentCustomProperties`),而不是走模块作用域的
406
+ * 全局声明。只有 `declare global { const … }` 时,`<script setup>` 里的自动导入照常工作,而
407
+ * **模板里**用同一个 helper 会报 `Property 'isPageCached' does not exist on type '{ $: … }'`。
408
+ *
409
+ * ubean 的 codegen 与 unplugin-auto-import 写的是同一份文件(谁后写谁赢),所以两边都必须产出
410
+ * 这段:codegen 只在 `prepare` / CLI dev / build 跑,unplugin 在每次 Vite dev/build 重写 ——
411
+ * 少一段就会出现「先跑 CLI 时红、跑过一次 dev 后变绿」这种漂移。
412
+ */
413
+ function buildTemplateAutoImportBlock(imports, resolveFrom) {
414
+ return [
415
+ "// for vue template auto import",
416
+ "import { UnwrapRef } from 'vue'",
417
+ "declare module 'vue' {",
418
+ " interface GlobalComponents {}",
419
+ " interface ComponentCustomProperties {",
420
+ ...imports.filter((imp) => imp.name && imp.from && imp.type !== true).map((imp) => ` readonly ${toDtsKey(imp.name)}: UnwrapRef<typeof import('${resolveFrom(imp.from)}')['${imp.name}']>`).sort(),
421
+ " }",
422
+ "}"
423
+ ].join("\n");
424
+ }
425
+ /**
426
+ * 生成 `.ubean/virtual-components.d.ts` —— 虚拟组件(配对/单边基名)的 ambient 声明。
427
+ *
428
+ * 为什么必须单独一份文件:这份内容会被 `unplugin-vue-components` 的重写丢掉(它只捞
429
+ * `GlobalComponents` 接口里的条目,周围的 `declare module` 语句一律不保留),而
430
+ * `components.d.ts` 正是它拥有的文件。
431
+ *
432
+ * 用**通配**说明符(`*foo.vue`)而不是相对路径:`declare module` 里的相对路径只在「说明符
433
+ * 字符串完全相同」时匹配,而同一个虚拟组件可以从任意目录、任意相对路径导入。通配声明只在
434
+ * TS 无法解析到真实文件时才生效,因此不会遮蔽真实 `.vue` 文件。
435
+ *
436
+ * 类型取服务端变体(配对与 server-only 都有),单边 `.client.vue` 则取客户端变体 —— 与
437
+ * 运行时首屏渲染的那一侧一致。
438
+ */
439
+ function generateVirtualComponentsDts(virtual, dtsPath) {
440
+ const dtsDir = fileDirname(toPosixPath(normalize(dtsPath)));
441
+ const lines = [
442
+ "// Auto-generated by ubean - do not edit manually",
443
+ "/* eslint-disable */",
444
+ "// @ts-nocheck",
445
+ "",
446
+ "// 本文件刻意保持 script(非模块)语义,让下面的声明成为全局 ambient 声明。",
447
+ ""
448
+ ];
449
+ const sorted = [...virtual].sort((a, b) => a.baseName.localeCompare(b.baseName));
450
+ for (const comp of sorted) {
451
+ const rel = toPosixPath(relative(dtsDir, toPosixPath(normalize(comp.typeSourcePath))));
452
+ lines.push(`// ${comp.name}:磁盘上没有 ${comp.baseName}.vue,由 @ubean/islands 按同名 .server.vue / .client.vue 合成`, `declare module '*${comp.baseName}.vue' {`, ` const component: typeof import('./${rel}')['default'];`, " export default component;", "}", "");
453
+ }
454
+ return `${lines.join("\n")}\n`;
455
+ }
456
+ /**
356
457
  * Generate the `.ubean/components.d.ts` in a format compatible with
357
458
  * unplugin-vue-components (both writers own the same file).
358
459
  *
@@ -390,12 +491,26 @@ function generateComponentsDts(components, dtsPath) {
390
491
  " export interface GlobalComponents {"
391
492
  ];
392
493
  const sorted = [...entries.entries()].sort(([a], [b]) => a.localeCompare(b));
393
- lines.push(...sorted.map(([name, declaration]) => ` ${name}: ${declaration}`));
494
+ lines.push(...sorted.map(([name, declaration]) => ` ${toDtsKey(name)}: ${declaration}`));
394
495
  lines.push(" }");
395
496
  lines.push("}");
396
497
  lines.push("");
397
498
  return `${lines.join("\n")}\n`;
398
499
  }
500
+ /**
501
+ * 接口成员名 → 合法的 TS 键。
502
+ *
503
+ * 名字里含 `.` 时(如 `My.Comp.vue` 这种文件名)直接写就是**限定名**,在接口里是语法
504
+ * 错误 —— 而语法错误不受本文件顶部 `@ts-nocheck` 影响,整个 d.ts 会连累项目 type-check。
505
+ * 加引号后是合法的字符串字面量键,且 unplugin-vue-components 重写时也用同样形式
506
+ * (实测它把非标识符名写成 `'My.Comp': …`),两边不会互相反复改写。
507
+ *
508
+ * 注意这里只改**写法**不改名字:名字必须与 unplugin 的派生结果一致,否则两个写入器
509
+ * 会各自重写同一份文件。
510
+ */
511
+ function toDtsKey(name) {
512
+ return /^[A-Za-z_$][\w$]*$/.test(name) ? name : JSON.stringify(name);
513
+ }
399
514
  function getBuiltinComposables() {
400
515
  const imports = [];
401
516
  for (const preset of BUILTIN_PRESETS) for (const name of preset.imports) if (typeof name === "string") imports.push({
@@ -725,6 +840,12 @@ const CODEGEN_FILES = [
725
840
  module: null,
726
841
  required: true,
727
842
  types: []
843
+ },
844
+ {
845
+ name: "virtual-components.d.ts",
846
+ module: null,
847
+ required: false,
848
+ types: []
728
849
  }
729
850
  ];
730
851
  async function generateTypes(result, options) {
@@ -741,13 +862,13 @@ async function generateTypes(result, options) {
741
862
  generated.push(pageTypesPath);
742
863
  const i18nTypesPath = await generateI18nTypes(result, { outDir });
743
864
  if (i18nTypesPath) generated.push(i18nTypesPath);
744
- const { autoImportsDtsPath, componentsDtsPath } = await generateAutoImports(result, {
865
+ const { autoImportsDtsPath, componentsDtsPath, virtualComponentsDtsPath } = await generateAutoImports(result, {
745
866
  cwd,
746
867
  srcDir,
747
868
  buildDir,
748
869
  ...autoImportOptions
749
870
  });
750
- generated.push(autoImportsDtsPath, componentsDtsPath);
871
+ generated.push(autoImportsDtsPath, componentsDtsPath, virtualComponentsDtsPath);
751
872
  const manifest = {
752
873
  contractVersion: 1,
753
874
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -765,8 +886,9 @@ async function generateTypes(result, options) {
765
886
  i18nTypesPath,
766
887
  autoImportsDtsPath,
767
888
  componentsDtsPath,
889
+ virtualComponentsDtsPath,
768
890
  generated
769
891
  };
770
892
  }
771
893
  //#endregion
772
- export { getUbeanComponentsConfig as C, toArray as E, getUbeanAutoImportConfig as S, resolveComponentsConfig as T, VUE_ROUTER_PRESET as _, generateOpenApiTypesFromServer as a, getAutoImportPresets as b, generateI18nTypes as c, HONO_OPENAPI_PRESET as d, UBEAN_CLIENT_PRESET as f, VUE_PRESET as g, VUE_MACROS_PRESET as h, generateOpenApiTypes as i, messagesToTsType as l, VUE_I18N_PRESET as m, CODEGEN_FILES as n, generatePageTypes as o, UBEAN_SERVER_PRESET as p, generateTypes as r, generateRouteTypes as s, CODEGEN_CONTRACT_VERSION as t, BUILTIN_PRESETS as u, generateAutoImports as v, resolveAutoImportsConfig as w, getBuiltinComposables as x, generateImportsTransform as y };
894
+ export { getUbeanAutoImportConfig as C, toArray as D, resolveComponentsConfig as E, getBuiltinComposables as S, resolveAutoImportsConfig as T, VUE_PRESET as _, generateOpenApiTypesFromServer as a, generateImportsTransform as b, generateI18nTypes as c, COMPONENT_HALF_GLOBS as d, HONO_OPENAPI_PRESET as f, VUE_MACROS_PRESET as g, VUE_I18N_PRESET as h, generateOpenApiTypes as i, messagesToTsType as l, UBEAN_SERVER_PRESET as m, CODEGEN_FILES as n, generatePageTypes as o, UBEAN_CLIENT_PRESET as p, generateTypes as r, generateRouteTypes as s, CODEGEN_CONTRACT_VERSION as t, BUILTIN_PRESETS as u, VUE_ROUTER_PRESET as v, getUbeanComponentsConfig as w, getAutoImportPresets as x, generateAutoImports as y };
@@ -1,2 +1,2 @@
1
- import { C as getPresetBuildConfig, S as generateVirtualModulesToDisk, T as buildWithEnvironments, b as generateNodeServerEntry, v as createIslandsSsrStubPlugin, w as serializePagesForEntry, x as generateStandardHandlerEntry, y as generateCloudflareWorkerEntry } from "./vite-DvHEv7Op.js";
1
+ import { C as getPresetBuildConfig, S as generateVirtualModulesToDisk, T as buildWithEnvironments, b as generateNodeServerEntry, v as createIslandsSsrStubPlugin, w as serializePagesForEntry, x as generateStandardHandlerEntry, y as generateCloudflareWorkerEntry } from "./vite-VaaeRB17.js";
2
2
  export { buildWithEnvironments, createIslandsSsrStubPlugin, generateCloudflareWorkerEntry, generateNodeServerEntry, generateStandardHandlerEntry, generateVirtualModulesToDisk, getPresetBuildConfig, serializePagesForEntry };
@@ -1,6 +1,7 @@
1
1
  import { a as ssrSingletonProdOptimizeExclude, m as createVirtualRegistry, o as ssrSingletonProdSsr, y as __exportAll } from "./ssr-singleton-DPTawJSx.js";
2
2
  import { a as createRoutingVirtualModule, i as createPagesVirtualModule, n as createLocalesVirtualModule, r as createMetaVirtualModule, s as transformMacros, t as createAppVirtualModule } from "./virtual-modules-CvGWlsXj.js";
3
- import { D as getDevScanCoordinator, a as createVueAppEntryVirtualModule, g as toWebRequest, h as sendWebResponse, i as createServerEntryVirtualModule, n as ubeanVite, o as createVuePagesVirtualModule, r as createClientEntryVirtualModule } from "./vue-BrbbaXTC.js";
3
+ import { i as generateOpenApiTypes, r as generateTypes } from "./codegen-Up8-XhRo.js";
4
+ import { _ as toWebRequest, a as createVueAppEntryVirtualModule, b as getDevScanCoordinator, g as sendWebResponse, i as createServerEntryVirtualModule, n as ubeanVite, o as createVuePagesVirtualModule, r as createClientEntryVirtualModule, u as ensureDevApp } from "./vue-CKAJjBBR.js";
4
5
  import { createStaticSsgRenderer } from "./static-render.js";
5
6
  import { prerender, resolvePrerenderStaticDir } from "./prerender.js";
6
7
  import { join, relative, resolve } from "pathe";
@@ -11,9 +12,9 @@ import { isEphemeralCachePreset, registerBuiltinPresets, resolvePresetByName, re
11
12
  import { createServerRouter } from "@ubean/routes";
12
13
  import { scanProject } from "@ubean/scan";
13
14
  import { getLogger } from "@ubean/shared/logger";
14
- import { getVueLocaleParam } from "@ubean/i18n";
15
15
  import * as nodeFsPromises from "node:fs/promises";
16
16
  import { cp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
17
+ import { getVueLocaleParam } from "@ubean/i18n";
17
18
  import { getColorModeScript, resolveColorModeConfig } from "@ubean/client";
18
19
  import { DevEnvironment, createBuilder, normalizePath, perEnvironmentPlugin } from "vite";
19
20
  import { ubeanIslandsPlugin } from "@ubean/islands/vite";
@@ -348,7 +349,7 @@ export async function renderStaticPage(input) {
348
349
  * 核心插件是唯一提供者,取值顺序为「调用方传入的内存 manifest(RM-V18 的传递)→ 服务端
349
350
  * outDir 旁的磁盘 manifest(`<outputDir>/public/.vite/manifest.json`)→ 空 + 构建期告警」。
350
351
  */
351
- const logger$5 = getLogger("build");
352
+ const logger$6 = getLogger("build");
352
353
  /** 本插件提供的虚拟模块 id。 */
353
354
  const ASSET_MANIFEST_VIRTUAL_ID = "virtual:ubean-asset-manifest";
354
355
  const RESOLVED_ID = `\0${ASSET_MANIFEST_VIRTUAL_ID}`;
@@ -434,7 +435,7 @@ function ubeanAssetManifestPlugin(getManifest, getServerOutDir) {
434
435
  load(id, options) {
435
436
  if (id !== RESOLVED_ID) return void 0;
436
437
  const { tags, source } = resolveInjectedAssetTags(getManifest(), getServerOutDir?.());
437
- if (source === "none") logger$5.warn(`${ASSET_MANIFEST_VIRTUAL_ID} 注入时没有可用的 client manifest(环境:${options?.ssr ? "server" : "client"})—— 产出的 HTML 将不含 asset tags。`);
438
+ if (source === "none") logger$6.warn(`${ASSET_MANIFEST_VIRTUAL_ID} 注入时没有可用的 client manifest(环境:${options?.ssr ? "server" : "client"})—— 产出的 HTML 将不含 asset tags。`);
438
439
  return `export const assetTags = ${JSON.stringify({
439
440
  ...tags,
440
441
  favicon: null
@@ -667,7 +668,7 @@ function isDirectory(path) {
667
668
  *
668
669
  * 这里只搬移、不改语义:所有行为与旧编排原先逐段一致。
669
670
  */
670
- const logger$4 = getLogger("build");
671
+ const logger$5 = getLogger("build");
671
672
  /** 产物目录布局(`dist/` 根、`dist/public`、`dist/server`,虚拟模块落 `.ubean/virtual`)。 */
672
673
  function getBuildOutDirs(cwd, outputDir) {
673
674
  const outputRoot = resolve(cwd, outputDir);
@@ -682,7 +683,7 @@ function getBuildOutDirs(cwd, outputDir) {
682
683
  /** 清空并重建产物目录(页面/服务端目录按 mode 决定是否创建)。 */
683
684
  async function cleanBuildOutput(options) {
684
685
  const { outDirs, hasPages, hasServer, mode, ssrEnabled } = options;
685
- logger$4.info(`Cleaning output directory... (mode=${mode}${mode === "fullstack" ? `, ssr=${ssrEnabled}` : ""})`);
686
+ logger$5.info(`Cleaning output directory... (mode=${mode}${mode === "fullstack" ? `, ssr=${ssrEnabled}` : ""})`);
686
687
  if (existsSync(outDirs.root)) await rm(outDirs.root, {
687
688
  recursive: true,
688
689
  force: true
@@ -751,7 +752,7 @@ ${tags.css ? ` ${tags.css.split("\n").join("\n ")}\n` : ""}</head>
751
752
  async function writePresetWrapper(options) {
752
753
  const { mode, presetBuildConfig, outDirs, entries } = options;
753
754
  if (mode === "ssg") {
754
- logger$4.info("SSG mode: skipping preset server wrapper (static output only)");
755
+ logger$5.info("SSG mode: skipping preset server wrapper (static output only)");
755
756
  return "entry.mjs";
756
757
  }
757
758
  if (presetBuildConfig.entryType === "node") {
@@ -775,7 +776,7 @@ assets = { directory = "./public" }
775
776
  `.trim();
776
777
  await writeFile(join(outDirs.root, "wrangler.toml"), wranglerToml, "utf-8");
777
778
  const unsupported = findUnsupportedNodeImports(outDirs.server);
778
- if (unsupported.length > 0) logger$4.warn(`worker 产物包含 workerd 不支持的 Node 内建导入(${unsupported.join("、")})—— Worker 运行时会在启动时直接失败。来源通常是仅 Node 可用的静态服务/文件系统路径。`);
779
+ if (unsupported.length > 0) logger$5.warn(`worker 产物包含 workerd 不支持的 Node 内建导入(${unsupported.join("、")})—— Worker 运行时会在启动时直接失败。来源通常是仅 Node 可用的静态服务/文件系统路径。`);
779
780
  return "worker.mjs";
780
781
  }
781
782
  await writeFile(join(outDirs.server, "handler.mjs"), entries.standard(), "utf-8");
@@ -799,11 +800,11 @@ async function writeBuildManifest(options) {
799
800
  preset: preset.name || "standard"
800
801
  };
801
802
  await writeFile(join(outDirs.root, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
802
- logger$4.info(`Build complete! Output: ${outDirs.root}`);
803
- if (hasPages) logger$4.info(` Client assets: ${outDirs.public}`);
803
+ logger$5.info(`Build complete! Output: ${outDirs.root}`);
804
+ if (hasPages) logger$5.info(` Client assets: ${outDirs.public}`);
804
805
  if (hasServer) {
805
- logger$4.info(` Server bundle: ${outDirs.server}`);
806
- logger$4.info(` Entry: ${serverEntry}`);
806
+ logger$5.info(` Server bundle: ${outDirs.server}`);
807
+ logger$5.info(` Entry: ${serverEntry}`);
807
808
  }
808
809
  return manifest;
809
810
  }
@@ -929,6 +930,79 @@ function createBuildEnvironments(input) {
929
930
  };
930
931
  }
931
932
  //#endregion
933
+ //#region src/vite/openapi-step.ts
934
+ /**
935
+ * 构建期生成 `.ubean/openapi.d.ts`(OpenAPI → TypeScript 类型)。
936
+ *
937
+ * **为什么需要这一步**:`/_openapi.json` 是 `generateSpecs(app, …)`(hono-openapi)从 Hono app
938
+ * 现算的,需要 routes 已经注册并加载完毕。`ubean dev` 靠「起 server 再 HTTP 拉一次」拿到它,
939
+ * 于是类型声明**只在跑过一次 dev 之后才存在** —— 干净检出下 `pnpm type-check` 会报一片
940
+ * `Cannot find module '../../.ubean/openapi'` 以及连带的 `pathParams`/`query` 类型不匹配
941
+ * (实测:示例项目因此在 CI 里根本没法把 type-check 变成门禁)。
942
+ *
943
+ * 构建产物里的 `entry.mjs` 恰好就是那份 app,所以这里发一个**进程内请求**取 schema:不发网络、
944
+ * 不依赖 dev server,与 `createSsrFetcher` 同源(同一条「import entry → createFetchHandler →
945
+ * 合成 `http://localhost<path>` 请求」的路子)。
946
+ *
947
+ * 放在 `runEnvBuilds` 里而不是 CLI:`ubean build` 与 `vite build` 两条路径都要产出它
948
+ * (ADR-0012 的产物一致性)。
949
+ */
950
+ const logger$4 = getLogger("build");
951
+ /**
952
+ * 从一个 app 的 `/_openapi.json` 生成类型声明(**进程内**请求,不走 HTTP)。
953
+ *
954
+ * 构建路径(`runOpenApiTypesStep`)与 dev 路径(核心插件的 `listening` 钩子,见
955
+ * `ensureDevApp`)共用这段:两者唯一的差别是 app 从哪来。
956
+ */
957
+ async function generateOpenApiTypesFromApp(app, options) {
958
+ const response = await app.fetch(new Request("http://localhost/_openapi.json"));
959
+ if (!response.ok) return { skipped: `/_openapi.json responded ${response.status}` };
960
+ if (!(response.headers.get("content-type") || "").includes("json")) return { skipped: "no JSON response" };
961
+ const schema = await response.json();
962
+ return { filePath: await generateOpenApiTypes(schema, { outDir: join(options.cwd, options.buildDir) }) };
963
+ }
964
+ /**
965
+ * 从构建好的 SSR entry 取 `/_openapi.json` 并生成类型声明。
966
+ *
967
+ * 任何一步不成立都**不抛错**:类型声明是 DX 产物,不该让构建失败(与预渲染的容错策略一致)。
968
+ * 无后端模式(ssg / spa)本就没有服务端产物或该路由返回 HTML,直接跳过。
969
+ */
970
+ async function runOpenApiTypesStep(options) {
971
+ const { cwd, manifest, buildDir } = options;
972
+ const entryPath = resolve(cwd, manifest.serverDir, "entry.mjs");
973
+ if (!existsSync(entryPath)) return { skipped: "no server entry" };
974
+ let mod;
975
+ try {
976
+ mod = await import(
977
+ /* @vite-ignore */
978
+ pathToFileURL(entryPath).href
979
+ );
980
+ } catch (err) {
981
+ logger$4.warn(`Failed to load SSR entry for OpenAPI types: ${err instanceof Error ? err.message : String(err)}`);
982
+ return { skipped: "entry import failed" };
983
+ }
984
+ try {
985
+ const createApp = mod.createApp;
986
+ if (typeof createApp !== "function") return { skipped: "no createApp export" };
987
+ const app = await createApp({ openAPI: {
988
+ scalarPath: "/_scalar",
989
+ openAPIPath: "/_openapi.json"
990
+ } });
991
+ if (typeof app?.fetch !== "function") return { skipped: "app.fetch not available" };
992
+ return await generateOpenApiTypesFromApp(app, {
993
+ cwd,
994
+ buildDir
995
+ });
996
+ } catch (err) {
997
+ logger$4.warn(`Failed to generate OpenAPI types: ${err instanceof Error ? err.message : String(err)}`);
998
+ return { skipped: "generation failed" };
999
+ } finally {
1000
+ try {
1001
+ await mod.close?.();
1002
+ } catch {}
1003
+ }
1004
+ }
1005
+ //#endregion
932
1006
  //#region src/vite/prerender-step.ts
933
1007
  /**
934
1008
  * 预渲染步骤(RM-V21 的最后一环)。
@@ -1254,6 +1328,15 @@ async function runEnvBuilds(builder, prepared) {
1254
1328
  manifest: builtManifest,
1255
1329
  contentSnapshot: prepared.contentSnapshot
1256
1330
  });
1331
+ if (hasServer) {
1332
+ const openApiResult = await runOpenApiTypesStep({
1333
+ cwd,
1334
+ manifest: builtManifest,
1335
+ buildDir: ".ubean"
1336
+ });
1337
+ if (openApiResult.filePath) logger$2.info(`OpenAPI types generated: ${openApiResult.filePath}`);
1338
+ else if (openApiResult.skipped) logger$2.info(`OpenAPI types skipped (${openApiResult.skipped}).`);
1339
+ }
1257
1340
  return builtManifest;
1258
1341
  }
1259
1342
  /**
@@ -2376,6 +2459,8 @@ async function buildEnvironmentsForConfig(config) {
2376
2459
  function ubeanPlugin(options) {
2377
2460
  const virtualRegistry = options?.registry ?? createVirtualRegistry();
2378
2461
  let ubeanConfig = options?.config ?? tryGetConfig() ?? void 0;
2462
+ /** 已跑过 codegen 的扫描结果(`buildStart` 会在两个环境各跑一次)。 */
2463
+ let lastCodegenScan = null;
2379
2464
  /** client manifest 的内存载体(RM-V18):`buildApp` 填、本插件的 load 读。 */
2380
2465
  const assetManifestRef = { current: null };
2381
2466
  let srcDirAbs = "";
@@ -2425,8 +2510,9 @@ function ubeanPlugin(options) {
2425
2510
  * `dist/{public,server,manifest.json}`。builder 与 environments 由 Vite 按本钩子创建,
2426
2511
  * 插件只跑拆分好的阶段(`prepareBuild` → `runEnvBuilds`),**不**自建 builder(会递归)。
2427
2512
  *
2428
- * 已知缺口:**预渲染**尚未接入本路径(`prerender()` 目前由 CLI 调用),因此
2429
- * `vite build` 的产物缺静态 HTML,与 `ubean build` 仍不等价(RM-V23 的矩阵会据此判定)。
2513
+ * 预渲染也在本路径内(`runEnvBuilds` → `runPrerenderStep`,同一份实现 CLI 路径也在用)。
2514
+ * 实测(2026-09,examples/ubean-test,`vp build` vs `ubean build`):产物树逐项一致,
2515
+ * 189 个文件全部对应,仅资源哈希不同 —— 别再照抄「`vite build` 缺静态 HTML」的旧结论。
2430
2516
  */
2431
2517
  builder: { async buildApp(builder) {
2432
2518
  const [{ createBuildContext, prepareBuild, runEnvBuilds }, { resolvePresetByName, registerBuiltinPresets }, { loadContentForBuild }] = await Promise.all([
@@ -2524,6 +2610,7 @@ function ubeanPlugin(options) {
2524
2610
  reload: () => server.ws.send({ type: "full-reload" })
2525
2611
  })).subscribe(async (result, changed) => {
2526
2612
  await applyScan(result);
2613
+ await runProjectCodegen(result);
2527
2614
  for (const mod of VIRTUAL_MODULES) {
2528
2615
  const module = server.moduleGraph.getModuleById(VIRTUAL_PREFIX + mod);
2529
2616
  if (module) server.moduleGraph.invalidateModule(module);
@@ -2534,6 +2621,24 @@ function ubeanPlugin(options) {
2534
2621
  data: { file }
2535
2622
  });
2536
2623
  });
2624
+ if (process.env.UBEAN_CODEGEN_BY_CLI !== "1") {
2625
+ const runOpenApiTypes = async () => {
2626
+ if (!ubeanConfig) return;
2627
+ try {
2628
+ const app = await ensureDevApp(server);
2629
+ if (!app) return;
2630
+ const result = await generateOpenApiTypesFromApp(app, {
2631
+ cwd: ubeanConfig.rootDir,
2632
+ buildDir: ".ubean"
2633
+ });
2634
+ if (result.filePath) logger.info(`OpenAPI types generated: ${result.filePath}`);
2635
+ } catch (err) {
2636
+ logger.warn(`Failed to generate OpenAPI types: ${err instanceof Error ? err.message : String(err)}`);
2637
+ }
2638
+ };
2639
+ if (server.httpServer) server.httpServer.once("listening", () => void runOpenApiTypes());
2640
+ else runOpenApiTypes();
2641
+ }
2537
2642
  },
2538
2643
  /**
2539
2644
  * RM-V24:`vite preview` 接管。
@@ -2557,7 +2662,41 @@ function ubeanPlugin(options) {
2557
2662
  }
2558
2663
  async function scanAndRegister() {
2559
2664
  if (!ubeanConfig) return;
2560
- await applyScan(await scanProjectOnce());
2665
+ const result = await scanProjectOnce();
2666
+ await applyScan(result);
2667
+ await runProjectCodegen(result);
2668
+ }
2669
+ /**
2670
+ * 生成项目类型声明(`.ubean/routes.d.ts`、`pages.d.ts`、`i18n.d.ts`、`auto-imports.d.ts`、
2671
+ * `components.d.ts`、`virtual-components.d.ts` …)。
2672
+ *
2673
+ * **为什么由插件负责**:此前只有 CLI(`ubean dev` / `build` / `prepare`)会跑这套 codegen,
2674
+ * 于是裸 Vite 路径(`vite dev` / `vite build`)下这些文件根本不生成 —— 用户的 type-check
2675
+ * 与编辑器补全直接不成立。实测:`vp build` 之后示例的 `pnpm type-check` 报
2676
+ * `Cannot find module '../components/sc/ThemeBadge.vue'`(虚拟组件声明缺失),以及
2677
+ * `routes.d.ts`/`pages.d.ts` 缺失导致的一连串类型错误。ADR-0012 说两条路径等价,
2678
+ * 那这一步也得在两条路径上都成立。
2679
+ *
2680
+ * 与 CLI 的分工:CLI 已经生成过时插件让位(`UBEAN_CODEGEN_BY_CLI` / 构建期的
2681
+ * `UBEAN_BUILD_DRIVEN_BY_CLI`),避免同一份产物被两个执行者反复重写。
2682
+ */
2683
+ async function runProjectCodegen(result) {
2684
+ if (!ubeanConfig) return;
2685
+ if (process.env.UBEAN_CODEGEN_BY_CLI === "1" || process.env.UBEAN_BUILD_DRIVEN_BY_CLI === "1") return;
2686
+ if (lastCodegenScan === result) return;
2687
+ lastCodegenScan = result;
2688
+ try {
2689
+ await generateTypes(result, {
2690
+ cwd: ubeanConfig.rootDir,
2691
+ srcDir: ubeanConfig.srcDir,
2692
+ buildDir: ".ubean",
2693
+ dirs: ubeanConfig.dir,
2694
+ autoImports: ubeanConfig.autoImports,
2695
+ components: ubeanConfig.components
2696
+ });
2697
+ } catch (err) {
2698
+ logger.warn(`Failed to generate type definitions: ${err instanceof Error ? err.message : String(err)}`);
2699
+ }
2561
2700
  }
2562
2701
  /**
2563
2702
  * 依据扫描结果重建路由/中间件注册与虚拟模块。与扫描分离(RM-V13):dev 下由
package/dist/vite.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { i as VirtualModuleResolver, o as createVirtualRegistry, r as VirtualModuleRegistry } from "./virtual-registry-CaU8k-YP.js";
2
2
  import { ResolvedConfig } from "@ubean/config";
3
3
  import { ScanResult, ScannedLayout, ScannedPageRoute } from "@ubean/scan";
4
+ import { UbeanApp } from "@ubean/app";
4
5
  import { Connect, DevEnvironment, DevEnvironmentContext, HotChannel, Logger, Plugin, ResolvedConfig as ResolvedConfig$1, ViteDevServer } from "vite";
5
6
  import { PageRenderer, PageRenderer as PageRenderer$1 } from "@ubean/pages";
6
- import { UbeanApp } from "@ubean/app";
7
7
  import { IncomingMessage, ServerResponse } from "node:http";
8
8
  //#region src/dev/dev-worker.d.ts
9
9
  /** 生成到 `.ubean/` 下的文件名。 */
@@ -199,6 +199,16 @@ interface DevBootstrapOptions {
199
199
  export declare function getDevApp(server: ViteDevServer): {
200
200
  fetch: (request: Request) => Response | Promise<Response>;
201
201
  } | undefined;
202
+ /**
203
+ * 按需触发自举(而不是等第一个请求),返回当前 app。
204
+ *
205
+ * 用途:裸 `vite dev` 下没有 CLI 去生成 OpenAPI 类型,而该类型来自 app 的 `/_openapi.json` ——
206
+ * 消费方(`@ubean/build` 的 dev openapi 步骤)需要能主动把 app 立起来,不能等页面请求。
207
+ * 与 `getDevApp` 一样挂在 server 对象上(插件与 CLI 可能持有不同的模块实例)。
208
+ */
209
+ export declare function ensureDevApp(server: ViteDevServer): Promise<{
210
+ fetch: (request: Request) => Response | Promise<Response>;
211
+ }> | undefined;
202
212
  interface DevRequestHandlers {
203
213
  /** `configureServer` 钩子体内使用:排在 Vite transform/静态中间件之前。 */
204
214
  pre: Connect.NextHandleFunction;
package/dist/vite.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import { m as createVirtualRegistry } from "./ssr-singleton-DPTawJSx.js";
2
- import { C as buildDevSsrRoutes, D as getDevScanCoordinator, E as createDevScanCoordinator, O as onDevScan, S as enhanceDevApp, T as DEV_SCAN_DIRS, _ as bootstrapDevApp, b as resolveDevSecurityHeaders, c as collectDevCssLinks, d as injectStylesheetLinks, f as isFrameworkHtmlPage, g as toWebRequest, h as sendWebResponse, k as peekDevScanCoordinator, l as createUbeanRequestHandlers, m as ubeanDevRequestPlugin, p as isViteResourceRequest, s as DEVTOOLS_PASS_THROUGH_PREFIXES, u as getDevApp, v as createDevApp, w as toVueRouterPagePath, x as resolveLocaleVueParam, y as createDevAppReady } from "./vue-BrbbaXTC.js";
3
- import { D as createCloudflarePreviewRunner, E as MINIFLARE_INSTALL_HINT, O as defaultLoadMiniflare, _ as ubeanPreviewPlugin, a as createEnvRunnerTransport, c as getDevWorkerEntrySource, d as attachPreviewMiddleware, f as createPreviewMiddleware, g as sendPreviewStatus, h as sendPreviewFile, i as bridgeEnvRunnerInvokes, k as readCompatibilityDate, l as invalidateDevWorkerModules, m as resolvePreviewFile, n as UBEAN_DEV_ENV_NAME, o as createUbeanDevEnvironmentFactory, p as previewMimeType, r as UbeanDevEnvironment, s as DEV_WORKER_FILE, t as ubeanPlugin, u as writeDevWorkerEntry } from "./vite-DvHEv7Op.js";
4
- export { DEVTOOLS_PASS_THROUGH_PREFIXES, DEV_SCAN_DIRS, DEV_WORKER_FILE, MINIFLARE_INSTALL_HINT, UBEAN_DEV_ENV_NAME, UbeanDevEnvironment, attachPreviewMiddleware, bootstrapDevApp, bridgeEnvRunnerInvokes, buildDevSsrRoutes, collectDevCssLinks, createCloudflarePreviewRunner, createDevApp, createDevAppReady, createDevScanCoordinator, createEnvRunnerTransport, createPreviewMiddleware, createUbeanDevEnvironmentFactory, createUbeanRequestHandlers, createVirtualRegistry, defaultLoadMiniflare, enhanceDevApp, getDevApp, getDevScanCoordinator, getDevWorkerEntrySource, injectStylesheetLinks, invalidateDevWorkerModules, isFrameworkHtmlPage, isViteResourceRequest, onDevScan, peekDevScanCoordinator, previewMimeType, readCompatibilityDate, resolveDevSecurityHeaders, resolveLocaleVueParam, resolvePreviewFile, sendPreviewFile, sendPreviewStatus, sendWebResponse, toVueRouterPagePath, toWebRequest, ubeanDevRequestPlugin, ubeanPlugin, ubeanPreviewPlugin, writeDevWorkerEntry };
2
+ import { A as toVueRouterPagePath, C as bootstrapDevApp, D as resolveLocaleVueParam, E as resolveDevSecurityHeaders, O as enhanceDevApp, S as peekDevScanCoordinator, T as createDevAppReady, _ as toWebRequest, b as getDevScanCoordinator, c as collectDevCssLinks, d as getDevApp, f as injectStylesheetLinks, g as sendWebResponse, h as ubeanDevRequestPlugin, k as buildDevSsrRoutes, l as createUbeanRequestHandlers, m as isViteResourceRequest, p as isFrameworkHtmlPage, s as DEVTOOLS_PASS_THROUGH_PREFIXES, u as ensureDevApp, v as DEV_SCAN_DIRS, w as createDevApp, x as onDevScan, y as createDevScanCoordinator } from "./vue-CKAJjBBR.js";
3
+ import { D as createCloudflarePreviewRunner, E as MINIFLARE_INSTALL_HINT, O as defaultLoadMiniflare, _ as ubeanPreviewPlugin, a as createEnvRunnerTransport, c as getDevWorkerEntrySource, d as attachPreviewMiddleware, f as createPreviewMiddleware, g as sendPreviewStatus, h as sendPreviewFile, i as bridgeEnvRunnerInvokes, k as readCompatibilityDate, l as invalidateDevWorkerModules, m as resolvePreviewFile, n as UBEAN_DEV_ENV_NAME, o as createUbeanDevEnvironmentFactory, p as previewMimeType, r as UbeanDevEnvironment, s as DEV_WORKER_FILE, t as ubeanPlugin, u as writeDevWorkerEntry } from "./vite-VaaeRB17.js";
4
+ export { DEVTOOLS_PASS_THROUGH_PREFIXES, DEV_SCAN_DIRS, DEV_WORKER_FILE, MINIFLARE_INSTALL_HINT, UBEAN_DEV_ENV_NAME, UbeanDevEnvironment, attachPreviewMiddleware, bootstrapDevApp, bridgeEnvRunnerInvokes, buildDevSsrRoutes, collectDevCssLinks, createCloudflarePreviewRunner, createDevApp, createDevAppReady, createDevScanCoordinator, createEnvRunnerTransport, createPreviewMiddleware, createUbeanDevEnvironmentFactory, createUbeanRequestHandlers, createVirtualRegistry, defaultLoadMiniflare, enhanceDevApp, ensureDevApp, getDevApp, getDevScanCoordinator, getDevWorkerEntrySource, injectStylesheetLinks, invalidateDevWorkerModules, isFrameworkHtmlPage, isViteResourceRequest, onDevScan, peekDevScanCoordinator, previewMimeType, readCompatibilityDate, resolveDevSecurityHeaders, resolveLocaleVueParam, resolvePreviewFile, sendPreviewFile, sendPreviewStatus, sendWebResponse, toVueRouterPagePath, toWebRequest, ubeanDevRequestPlugin, ubeanPlugin, ubeanPreviewPlugin, writeDevWorkerEntry };
@@ -1,9 +1,10 @@
1
1
  import { c as getComponentResolvers, h as defineVirtualModule, i as ssrSingletonDevPolicy, l as getCssImports, m as createVirtualRegistry } from "./ssr-singleton-DPTawJSx.js";
2
- import { E as toArray, T as resolveComponentsConfig, b as getAutoImportPresets, w as resolveAutoImportsConfig } from "./codegen-B3oGeRtK.js";
2
+ import { D as toArray, E as resolveComponentsConfig, T as resolveAutoImportsConfig, d as COMPONENT_HALF_GLOBS, x as getAutoImportPresets } from "./codegen-Up8-XhRo.js";
3
3
  import { createRequire } from "node:module";
4
4
  import { join, resolve } from "pathe";
5
5
  import { loadUbeanConfig } from "@ubean/config";
6
6
  import { scanProject } from "@ubean/scan";
7
+ import { applyServerConfig, createUbeanApp } from "@ubean/app";
7
8
  import { getVueLocaleParam, toVueRouterLocalePath } from "@ubean/i18n";
8
9
  import { getColorModeScript, getPartyTownScript, resolveColorModeConfig, resolvePartyTownConfig } from "@ubean/client";
9
10
  import { transformWithOxc } from "vite";
@@ -14,201 +15,7 @@ import AutoImport from "unplugin-auto-import/vite";
14
15
  import { ubeanMdxPlugin } from "@ubean/markdown";
15
16
  import { renderFaviconLink } from "@ubean/pages";
16
17
  import VueI18nPlugin from "@intlify/unplugin-vue-i18n/vite";
17
- import { applyServerConfig, createUbeanApp } from "@ubean/app";
18
18
  import { generatePagesModuleSource } from "@ubean/vue/vite";
19
- //#region src/dev/dev-scan.ts
20
- /** 触发扫描的目录名(相对 `srcDir`)。并集来自 core 与 vue 两个插件此前的清单。 */
21
- const DEV_SCAN_DIRS = [
22
- "routes",
23
- "middleware",
24
- "pages",
25
- "layouts",
26
- "plugins",
27
- "app",
28
- "api",
29
- "locales"
30
- ];
31
- const SCAN_FILE_EXTENSIONS = /\.(ts|js|mjs|cjs|mts|cts|vue|json|md|mdx)$/;
32
- /**
33
- * `srcDir` **根部**的入口文件名(`app.ts` / `app.vue` / `App.vue` / `server.ts` /
34
- * `server.dev.ts` …)。它们不在任何被监听的目录里,却同样决定服务端行为
35
- * (appRoot、defineApp、defineServer),因此必须纳入判据。
36
- *
37
- * 用静态规则而不是「等第一次扫描拿到 appEntry 再登记」:后者在入口文件本身是第一个改动对象时
38
- * 会漏掉 —— 首次扫描永远等不到,入口文件也就永远进不了监听集合(这正是此前「改 app.ts
39
- * 完全不触发重扫」的缺陷)。
40
- */
41
- const ENTRY_FILE_PATTERN = /^(app|App)(\.(server|client))?\.(ts|js|mjs|mts|vue)$|^server(\.(dev|prod))?\.(ts|js|mjs|mts)$/;
42
- function createDevScanCoordinator(options) {
43
- const { rootDir, source, debounceMs = 150 } = options;
44
- const srcDir = options.srcDir.startsWith("/") ? options.srcDir : `${rootDir}/${options.srcDir}`;
45
- const srcDirNormalized = srcDir.replace(/\/+$/, "");
46
- const subscribers = /* @__PURE__ */ new Set();
47
- const pending = /* @__PURE__ */ new Set();
48
- let debounceTimer = null;
49
- let running = null;
50
- let rerunRequested = false;
51
- let started = false;
52
- const warn = options.onError ?? ((error) => console.error("[ubean] scan failed:", error));
53
- /** 扫描目录(绝对)与「额外监听的文件」(入口文件,由扫描结果给出)。 */
54
- const scanDirPaths = DEV_SCAN_DIRS.map((dir) => `${srcDirNormalized}/${dir}`);
55
- const extraWatchFiles = /* @__PURE__ */ new Set();
56
- function isIgnored(file) {
57
- if (file.startsWith(".ubean/") || file.includes("/.ubean/")) return true;
58
- if (file.includes("/node_modules/") || file.includes("/.git/")) return true;
59
- if (file.endsWith(".bak")) return true;
60
- return (options.ignore ?? []).some((pattern) => file.includes(pattern.replace(/\*/g, "")));
61
- }
62
- /**
63
- * 事件是否与扫描相关。
64
- *
65
- * 判据是**绝对路径**(Vite 的 watcher 给的就是绝对路径):早先 CLI 那套监听自己把
66
- * `srcDir` 与事件名拼成路径,`path.join` 遇到绝对路径不重置导致拼出 `<cwd><cwd>/src/...`,
67
- * 所有监听目标 ENOENT 且异常被吞 —— 表现为「服务端改动完全不生效」。这里不做任何路径拼接。
68
- */
69
- function isScanRelevant(file) {
70
- if (!file.endsWith(".vue") && !SCAN_FILE_EXTENSIONS.test(file)) return false;
71
- if (extraWatchFiles.has(file)) return true;
72
- if (!file.startsWith(`${srcDirNormalized}/`)) return false;
73
- const rest = file.slice(srcDirNormalized.length + 1);
74
- if (DEV_SCAN_DIRS.includes(rest.split("/")[0])) return true;
75
- return !rest.includes("/") && ENTRY_FILE_PATTERN.test(rest);
76
- }
77
- function registerExtraFiles(result) {
78
- const entries = [
79
- result.appEntry?.shared,
80
- result.appEntry?.server,
81
- result.appEntry?.client,
82
- result.appEntry?.root,
83
- result.serverEntry?.shared,
84
- result.serverEntry?.dev,
85
- result.serverEntry?.prod
86
- ];
87
- for (const entry of entries) if (entry?.exists && entry.fullPath && !extraWatchFiles.has(entry.fullPath)) {
88
- extraWatchFiles.add(entry.fullPath);
89
- source.add(entry.fullPath);
90
- }
91
- }
92
- async function runScan(changed) {
93
- const result = await (options.scan ?? (() => scanProject({
94
- cwd: rootDir,
95
- srcDir,
96
- dirs: options.dirs,
97
- ignore: options.ignore
98
- })))();
99
- registerExtraFiles(result);
100
- for (const subscriber of subscribers) await subscriber(result, changed);
101
- options.reload?.();
102
- return result;
103
- }
104
- async function rescan(changed = []) {
105
- if (running) {
106
- rerunRequested = true;
107
- return running;
108
- }
109
- running = runScan(changed).catch((error) => {
110
- warn(error);
111
- throw error;
112
- });
113
- try {
114
- return await running;
115
- } finally {
116
- running = null;
117
- if (rerunRequested) {
118
- rerunRequested = false;
119
- rescan([...pending]).catch(() => {});
120
- }
121
- }
122
- }
123
- function queue(file) {
124
- pending.add(file);
125
- if (debounceTimer) clearTimeout(debounceTimer);
126
- debounceTimer = setTimeout(() => {
127
- debounceTimer = null;
128
- const changed = [...pending];
129
- pending.clear();
130
- rescan(changed).catch(() => {});
131
- }, debounceMs);
132
- }
133
- const onFileEvent = (file) => {
134
- if (isIgnored(file) || !isScanRelevant(file)) return;
135
- queue(file);
136
- };
137
- return {
138
- subscribe(fn) {
139
- subscribers.add(fn);
140
- return () => subscribers.delete(fn);
141
- },
142
- start() {
143
- if (started) return;
144
- started = true;
145
- for (const dir of scanDirPaths) source.add(dir);
146
- source.on("add", onFileEvent);
147
- source.on("unlink", onFileEvent);
148
- source.on("change", onFileEvent);
149
- },
150
- rescan,
151
- subscriberCount: () => subscribers.size,
152
- stop() {
153
- if (!started) return;
154
- started = false;
155
- source.off?.("add", onFileEvent);
156
- source.off?.("unlink", onFileEvent);
157
- source.off?.("change", onFileEvent);
158
- if (debounceTimer) {
159
- clearTimeout(debounceTimer);
160
- debounceTimer = null;
161
- }
162
- pending.clear();
163
- }
164
- };
165
- }
166
- const SCAN_STATE_KEY = "__ubeanScanState";
167
- function scanStateOf(server) {
168
- const holder = server;
169
- holder[SCAN_STATE_KEY] ??= {};
170
- return holder[SCAN_STATE_KEY];
171
- }
172
- /**
173
- * 取(或建立)该 dev server 的协调器。
174
- *
175
- * core 与 vue 插件都调用它,因此**先到的那个**负责建实例;后到的拿同一个。
176
- * `init` 只在首次调用时执行。
177
- */
178
- function getDevScanCoordinator(server, init) {
179
- const state = scanStateOf(server);
180
- if (state.coordinator) return state.coordinator;
181
- const coordinator = createDevScanCoordinator(init(server.watcher));
182
- state.coordinator = coordinator;
183
- if (state.pending) {
184
- for (const fn of state.pending) coordinator.subscribe(fn);
185
- state.pending = void 0;
186
- }
187
- coordinator.start();
188
- return coordinator;
189
- }
190
- /**
191
- * 取该 dev server **已存在**的协调器(不存在返回 undefined)。
192
- *
193
- * 给「只想触发一次扫描」的调用方用(CLI 的 `rescan()`):`getDevScanCoordinator` 需要 init
194
- * 参数、会在缺失时建实例,不适合这里。
195
- */
196
- function peekDevScanCoordinator(server) {
197
- return scanStateOf(server).coordinator;
198
- }
199
- /**
200
- * 订阅 dev 扫描(CLI 用:每次扫描后重建 Hono app 并让浏览器重载)。
201
- *
202
- * 允许在协调器建立之前订阅:`getDevScanCoordinator` 会把已登记的订阅转交给新实例。
203
- */
204
- function onDevScan(server, handler) {
205
- const state = scanStateOf(server);
206
- if (state.coordinator) return state.coordinator.subscribe(handler);
207
- state.pending ??= /* @__PURE__ */ new Set();
208
- state.pending.add(handler);
209
- return () => state.pending?.delete(handler);
210
- }
211
- //#endregion
212
19
  //#region src/dev/dev-ssr-routes.ts
213
20
  /**
214
21
  * dev/SSR 路由表(RM-V11 的组成部件,从 CLI dev server 抽出)。
@@ -587,6 +394,199 @@ function resolveLocaleVueParam(config) {
587
394
  });
588
395
  }
589
396
  //#endregion
397
+ //#region src/dev/dev-scan.ts
398
+ /** 触发扫描的目录名(相对 `srcDir`)。并集来自 core 与 vue 两个插件此前的清单。 */
399
+ const DEV_SCAN_DIRS = [
400
+ "routes",
401
+ "middleware",
402
+ "pages",
403
+ "layouts",
404
+ "plugins",
405
+ "app",
406
+ "api",
407
+ "locales"
408
+ ];
409
+ const SCAN_FILE_EXTENSIONS = /\.(ts|js|mjs|cjs|mts|cts|vue|json|md|mdx)$/;
410
+ /**
411
+ * `srcDir` **根部**的入口文件名(`app.ts` / `app.vue` / `App.vue` / `server.ts` /
412
+ * `server.dev.ts` …)。它们不在任何被监听的目录里,却同样决定服务端行为
413
+ * (appRoot、defineApp、defineServer),因此必须纳入判据。
414
+ *
415
+ * 用静态规则而不是「等第一次扫描拿到 appEntry 再登记」:后者在入口文件本身是第一个改动对象时
416
+ * 会漏掉 —— 首次扫描永远等不到,入口文件也就永远进不了监听集合(这正是此前「改 app.ts
417
+ * 完全不触发重扫」的缺陷)。
418
+ */
419
+ const ENTRY_FILE_PATTERN = /^(app|App)(\.(server|client))?\.(ts|js|mjs|mts|vue)$|^server(\.(dev|prod))?\.(ts|js|mjs|mts)$/;
420
+ function createDevScanCoordinator(options) {
421
+ const { rootDir, source, debounceMs = 150 } = options;
422
+ const srcDir = options.srcDir.startsWith("/") ? options.srcDir : `${rootDir}/${options.srcDir}`;
423
+ const srcDirNormalized = srcDir.replace(/\/+$/, "");
424
+ const subscribers = /* @__PURE__ */ new Set();
425
+ const pending = /* @__PURE__ */ new Set();
426
+ let debounceTimer = null;
427
+ let running = null;
428
+ let rerunRequested = false;
429
+ let started = false;
430
+ const warn = options.onError ?? ((error) => console.error("[ubean] scan failed:", error));
431
+ /** 扫描目录(绝对)与「额外监听的文件」(入口文件,由扫描结果给出)。 */
432
+ const scanDirPaths = DEV_SCAN_DIRS.map((dir) => `${srcDirNormalized}/${dir}`);
433
+ const extraWatchFiles = /* @__PURE__ */ new Set();
434
+ function isIgnored(file) {
435
+ if (file.startsWith(".ubean/") || file.includes("/.ubean/")) return true;
436
+ if (file.includes("/node_modules/") || file.includes("/.git/")) return true;
437
+ if (file.endsWith(".bak")) return true;
438
+ return (options.ignore ?? []).some((pattern) => file.includes(pattern.replace(/\*/g, "")));
439
+ }
440
+ /**
441
+ * 事件是否与扫描相关。
442
+ *
443
+ * 判据是**绝对路径**(Vite 的 watcher 给的就是绝对路径):早先 CLI 那套监听自己把
444
+ * `srcDir` 与事件名拼成路径,`path.join` 遇到绝对路径不重置导致拼出 `<cwd><cwd>/src/...`,
445
+ * 所有监听目标 ENOENT 且异常被吞 —— 表现为「服务端改动完全不生效」。这里不做任何路径拼接。
446
+ */
447
+ function isScanRelevant(file) {
448
+ if (!file.endsWith(".vue") && !SCAN_FILE_EXTENSIONS.test(file)) return false;
449
+ if (extraWatchFiles.has(file)) return true;
450
+ if (!file.startsWith(`${srcDirNormalized}/`)) return false;
451
+ const rest = file.slice(srcDirNormalized.length + 1);
452
+ if (DEV_SCAN_DIRS.includes(rest.split("/")[0])) return true;
453
+ return !rest.includes("/") && ENTRY_FILE_PATTERN.test(rest);
454
+ }
455
+ function registerExtraFiles(result) {
456
+ const entries = [
457
+ result.appEntry?.shared,
458
+ result.appEntry?.server,
459
+ result.appEntry?.client,
460
+ result.appEntry?.root,
461
+ result.serverEntry?.shared,
462
+ result.serverEntry?.dev,
463
+ result.serverEntry?.prod
464
+ ];
465
+ for (const entry of entries) if (entry?.exists && entry.fullPath && !extraWatchFiles.has(entry.fullPath)) {
466
+ extraWatchFiles.add(entry.fullPath);
467
+ source.add(entry.fullPath);
468
+ }
469
+ }
470
+ async function runScan(changed) {
471
+ const result = await (options.scan ?? (() => scanProject({
472
+ cwd: rootDir,
473
+ srcDir,
474
+ dirs: options.dirs,
475
+ ignore: options.ignore
476
+ })))();
477
+ registerExtraFiles(result);
478
+ for (const subscriber of subscribers) await subscriber(result, changed);
479
+ options.reload?.();
480
+ return result;
481
+ }
482
+ async function rescan(changed = []) {
483
+ if (running) {
484
+ rerunRequested = true;
485
+ return running;
486
+ }
487
+ running = runScan(changed).catch((error) => {
488
+ warn(error);
489
+ throw error;
490
+ });
491
+ try {
492
+ return await running;
493
+ } finally {
494
+ running = null;
495
+ if (rerunRequested) {
496
+ rerunRequested = false;
497
+ rescan([...pending]).catch(() => {});
498
+ }
499
+ }
500
+ }
501
+ function queue(file) {
502
+ pending.add(file);
503
+ if (debounceTimer) clearTimeout(debounceTimer);
504
+ debounceTimer = setTimeout(() => {
505
+ debounceTimer = null;
506
+ const changed = [...pending];
507
+ pending.clear();
508
+ rescan(changed).catch(() => {});
509
+ }, debounceMs);
510
+ }
511
+ const onFileEvent = (file) => {
512
+ if (isIgnored(file) || !isScanRelevant(file)) return;
513
+ queue(file);
514
+ };
515
+ return {
516
+ subscribe(fn) {
517
+ subscribers.add(fn);
518
+ return () => subscribers.delete(fn);
519
+ },
520
+ start() {
521
+ if (started) return;
522
+ started = true;
523
+ for (const dir of scanDirPaths) source.add(dir);
524
+ source.on("add", onFileEvent);
525
+ source.on("unlink", onFileEvent);
526
+ source.on("change", onFileEvent);
527
+ },
528
+ rescan,
529
+ subscriberCount: () => subscribers.size,
530
+ stop() {
531
+ if (!started) return;
532
+ started = false;
533
+ source.off?.("add", onFileEvent);
534
+ source.off?.("unlink", onFileEvent);
535
+ source.off?.("change", onFileEvent);
536
+ if (debounceTimer) {
537
+ clearTimeout(debounceTimer);
538
+ debounceTimer = null;
539
+ }
540
+ pending.clear();
541
+ }
542
+ };
543
+ }
544
+ const SCAN_STATE_KEY = "__ubeanScanState";
545
+ function scanStateOf(server) {
546
+ const holder = server;
547
+ holder[SCAN_STATE_KEY] ??= {};
548
+ return holder[SCAN_STATE_KEY];
549
+ }
550
+ /**
551
+ * 取(或建立)该 dev server 的协调器。
552
+ *
553
+ * core 与 vue 插件都调用它,因此**先到的那个**负责建实例;后到的拿同一个。
554
+ * `init` 只在首次调用时执行。
555
+ */
556
+ function getDevScanCoordinator(server, init) {
557
+ const state = scanStateOf(server);
558
+ if (state.coordinator) return state.coordinator;
559
+ const coordinator = createDevScanCoordinator(init(server.watcher));
560
+ state.coordinator = coordinator;
561
+ if (state.pending) {
562
+ for (const fn of state.pending) coordinator.subscribe(fn);
563
+ state.pending = void 0;
564
+ }
565
+ coordinator.start();
566
+ return coordinator;
567
+ }
568
+ /**
569
+ * 取该 dev server **已存在**的协调器(不存在返回 undefined)。
570
+ *
571
+ * 给「只想触发一次扫描」的调用方用(CLI 的 `rescan()`):`getDevScanCoordinator` 需要 init
572
+ * 参数、会在缺失时建实例,不适合这里。
573
+ */
574
+ function peekDevScanCoordinator(server) {
575
+ return scanStateOf(server).coordinator;
576
+ }
577
+ /**
578
+ * 订阅 dev 扫描(CLI 用:每次扫描后重建 Hono app 并让浏览器重载)。
579
+ *
580
+ * 允许在协调器建立之前订阅:`getDevScanCoordinator` 会把已登记的订阅转交给新实例。
581
+ */
582
+ function onDevScan(server, handler) {
583
+ const state = scanStateOf(server);
584
+ if (state.coordinator) return state.coordinator.subscribe(handler);
585
+ state.pending ??= /* @__PURE__ */ new Set();
586
+ state.pending.add(handler);
587
+ return () => state.pending?.delete(handler);
588
+ }
589
+ //#endregion
590
590
  //#region src/dev/node-web.ts
591
591
  /**
592
592
  * `node:http` 请求 → Web `Request`。
@@ -862,6 +862,19 @@ const DEV_APP_KEY = "__ubeanDevApp";
862
862
  function getDevApp(server) {
863
863
  return server[DEV_APP_KEY];
864
864
  }
865
+ /**
866
+ * 按需触发自举(而不是等第一个请求),返回当前 app。
867
+ *
868
+ * 用途:裸 `vite dev` 下没有 CLI 去生成 OpenAPI 类型,而该类型来自 app 的 `/_openapi.json` ——
869
+ * 消费方(`@ubean/build` 的 dev openapi 步骤)需要能主动把 app 立起来,不能等页面请求。
870
+ * 与 `getDevApp` 一样挂在 server 对象上(插件与 CLI 可能持有不同的模块实例)。
871
+ */
872
+ function ensureDevApp(server) {
873
+ const ensure = server[DEV_ENSURE_KEY];
874
+ return ensure?.();
875
+ }
876
+ /** `ensureDevApp` 在 server 对象上的键(由 `createLazyBootstrapHandler` 登记)。 */
877
+ const DEV_ENSURE_KEY = "__ubeanEnsureDevApp";
865
878
  function createLazyBootstrapHandler(server, options = {}) {
866
879
  let bootstrapPromise = null;
867
880
  const start = async () => {
@@ -878,7 +891,7 @@ function createLazyBootstrapHandler(server, options = {}) {
878
891
  onDevScan(server, async (result) => {
879
892
  await (await bootstrapPromise?.catch(() => null))?.rebuild(result);
880
893
  });
881
- return async (request) => {
894
+ const ensureBootstrap = async () => {
882
895
  bootstrapPromise ??= start().then((bootstrap) => {
883
896
  server[DEV_APP_KEY] = bootstrap.app;
884
897
  return bootstrap;
@@ -886,7 +899,11 @@ function createLazyBootstrapHandler(server, options = {}) {
886
899
  const bootstrap = await bootstrapPromise;
887
900
  await bootstrap.ready();
888
901
  server[DEV_APP_KEY] = bootstrap.app;
889
- return bootstrap.app.fetch(request);
902
+ return bootstrap;
903
+ };
904
+ server[DEV_ENSURE_KEY] = async () => (await ensureBootstrap()).app;
905
+ return async (request) => {
906
+ return (await ensureBootstrap()).app.fetch(request);
890
907
  };
891
908
  }
892
909
  /** 500 错误页。dev 才看得到,直接给可读的原文与栈。 */
@@ -1666,11 +1683,13 @@ function ubeanVite(options) {
1666
1683
  dirs: componentsDirs,
1667
1684
  extensions,
1668
1685
  include: includePatterns,
1686
+ globsExclude: [...toArray(userComponents.globsExclude), ...COMPONENT_HALF_GLOBS],
1669
1687
  dts: userComponents.dts === void 0 ? join(dtsDir, "components.d.ts") : userComponents.dts,
1670
1688
  resolvers: [...dynamicResolvers, ...toArray(userComponents.resolvers)]
1671
1689
  }));
1672
1690
  } else plugins.push(Components({
1673
1691
  dts: true,
1692
+ globsExclude: COMPONENT_HALF_GLOBS,
1674
1693
  resolvers: dynamicResolvers
1675
1694
  }));
1676
1695
  const searchConfig = ubeanConfig.search;
@@ -1726,4 +1745,4 @@ async function runPagefindIndexing(ubeanConfig, searchConfig) {
1726
1745
  });
1727
1746
  }
1728
1747
  //#endregion
1729
- export { buildDevSsrRoutes as C, getDevScanCoordinator as D, createDevScanCoordinator as E, onDevScan as O, enhanceDevApp as S, DEV_SCAN_DIRS as T, bootstrapDevApp as _, createVueAppEntryVirtualModule as a, resolveDevSecurityHeaders as b, collectDevCssLinks as c, injectStylesheetLinks as d, isFrameworkHtmlPage as f, toWebRequest as g, sendWebResponse as h, createServerEntryVirtualModule as i, peekDevScanCoordinator as k, createUbeanRequestHandlers as l, ubeanDevRequestPlugin as m, ubeanVite as n, createVuePagesVirtualModule as o, isViteResourceRequest as p, createClientEntryVirtualModule as r, DEVTOOLS_PASS_THROUGH_PREFIXES as s, VUE_PLUGIN_INCLUDE as t, getDevApp as u, createDevApp as v, toVueRouterPagePath as w, resolveLocaleVueParam as x, createDevAppReady as y };
1748
+ export { toVueRouterPagePath as A, bootstrapDevApp as C, resolveLocaleVueParam as D, resolveDevSecurityHeaders as E, enhanceDevApp as O, peekDevScanCoordinator as S, createDevAppReady as T, toWebRequest as _, createVueAppEntryVirtualModule as a, getDevScanCoordinator as b, collectDevCssLinks as c, getDevApp as d, injectStylesheetLinks as f, sendWebResponse as g, ubeanDevRequestPlugin as h, createServerEntryVirtualModule as i, buildDevSsrRoutes as k, createUbeanRequestHandlers as l, isViteResourceRequest as m, ubeanVite as n, createVuePagesVirtualModule as o, isFrameworkHtmlPage as p, createClientEntryVirtualModule as r, DEVTOOLS_PASS_THROUGH_PREFIXES as s, VUE_PLUGIN_INCLUDE as t, ensureDevApp as u, DEV_SCAN_DIRS as v, createDevApp as w, onDevScan as x, createDevScanCoordinator as y };
package/dist/vue.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as createVueAppEntryVirtualModule, i as createServerEntryVirtualModule, n as ubeanVite, o as createVuePagesVirtualModule, r as createClientEntryVirtualModule, t as VUE_PLUGIN_INCLUDE } from "./vue-BrbbaXTC.js";
1
+ import { a as createVueAppEntryVirtualModule, i as createServerEntryVirtualModule, n as ubeanVite, o as createVuePagesVirtualModule, r as createClientEntryVirtualModule, t as VUE_PLUGIN_INCLUDE } from "./vue-CKAJjBBR.js";
2
2
  export { VUE_PLUGIN_INCLUDE, createClientEntryVirtualModule, createServerEntryVirtualModule, createVueAppEntryVirtualModule, createVuePagesVirtualModule, ubeanVite as default, ubeanVite };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ubean/build",
3
- "version": "0.6.0-beta.1",
3
+ "version": "0.6.0-beta.2",
4
4
  "description": "Vite plugins, production build, SSG prerender, type codegen, and Server Actions plugin for ubean",
5
5
  "files": [
6
6
  "dist"
@@ -45,20 +45,20 @@
45
45
  },
46
46
  "dependencies": {
47
47
  "@intlify/unplugin-vue-i18n": "11.2.5",
48
- "@ubean/app": "0.6.0-beta.1",
49
- "@ubean/client": "0.6.0-beta.1",
50
- "@ubean/config": "0.6.0-beta.1",
51
- "@ubean/i18n": "0.6.0-beta.1",
52
- "@ubean/islands": "0.6.0-beta.1",
53
- "@ubean/markdown": "0.6.0-beta.1",
54
- "@ubean/pages": "0.6.0-beta.1",
55
- "@ubean/preset": "0.6.0-beta.1",
56
- "@ubean/routes": "0.6.0-beta.1",
57
- "@ubean/scan": "0.6.0-beta.1",
58
- "@ubean/server": "0.6.0-beta.1",
59
- "@ubean/shared": "0.6.0-beta.1",
60
- "@ubean/vue": "0.6.0-beta.1",
61
- "@vitejs/plugin-vue": "^6.0.8",
48
+ "@ubean/app": "0.6.0-beta.2",
49
+ "@ubean/client": "0.6.0-beta.2",
50
+ "@ubean/config": "0.6.0-beta.2",
51
+ "@ubean/i18n": "0.6.0-beta.2",
52
+ "@ubean/islands": "0.6.0-beta.2",
53
+ "@ubean/markdown": "0.6.0-beta.2",
54
+ "@ubean/pages": "0.6.0-beta.2",
55
+ "@ubean/preset": "0.6.0-beta.2",
56
+ "@ubean/routes": "0.6.0-beta.2",
57
+ "@ubean/scan": "0.6.0-beta.2",
58
+ "@ubean/server": "0.6.0-beta.2",
59
+ "@ubean/shared": "0.6.0-beta.2",
60
+ "@ubean/vue": "0.6.0-beta.2",
61
+ "@vitejs/plugin-vue": "^6.0.9",
62
62
  "openapi-typescript": "^7.13.0",
63
63
  "pathe": "^2.0.3",
64
64
  "tinyglobby": "^0.2.17",
@@ -66,17 +66,17 @@
66
66
  "unplugin-auto-import": "21.1.0",
67
67
  "unplugin-vue-components": "^32.1.0",
68
68
  "unplugin-vue-markdown": "^32.1.1",
69
- "vue-i18n": "11.4.10"
69
+ "vue-i18n": "11.4.12"
70
70
  },
71
71
  "devDependencies": {
72
- "@types/node": "^26.5.0",
73
- "hono": "4.13.7",
72
+ "@types/node": "^26.6.1",
73
+ "hono": "4.13.8",
74
74
  "typescript": "npm:typescript-native-bridge@latest",
75
- "vite": "npm:@voidzero-dev/vite-plus-core@0.3.1",
76
- "vite-plus": "0.3.1"
75
+ "vite": "npm:@voidzero-dev/vite-plus-core@0.3.3",
76
+ "vite-plus": "0.3.3"
77
77
  },
78
78
  "peerDependencies": {
79
- "vite": "npm:@voidzero-dev/vite-plus-core@0.3.1"
79
+ "vite": "npm:@voidzero-dev/vite-plus-core@0.3.3"
80
80
  },
81
81
  "peerDependenciesMeta": {
82
82
  "vite": {