@ubean/build 0.5.2 → 0.6.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions-plugin.js +55 -6
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -4
- package/dist/prerender.d.ts +13 -1
- package/dist/prerender.js +19 -4
- package/dist/production.d.ts +58 -2
- package/dist/production.js +2 -905
- package/dist/ssr-singleton-DPTawJSx.js +218 -0
- package/dist/static-render.js +1 -1
- package/dist/{virtual-modules-vLkLkAfT.js → virtual-modules-CvGWlsXj.js} +18 -2
- package/dist/virtual-registry-CaU8k-YP.d.ts +53 -0
- package/dist/vite-DvHEv7Op.js +2656 -0
- package/dist/vite.d.ts +618 -27
- package/dist/vite.js +4 -2
- package/dist/vue-BrbbaXTC.js +1729 -0
- package/dist/vue.d.ts +14 -1
- package/dist/vue.js +1 -1
- package/package.json +14 -12
- package/dist/ssr-singleton-CEQi_H6-.js +0 -113
- package/dist/virtual-registry-BF0jYPle.d.ts +0 -30
- package/dist/virtual-registry-BWkaQHXN.js +0 -69
- package/dist/vite-D2EZl_6P.js +0 -226
- package/dist/vue-DcydGsvy.js +0 -723
package/dist/actions-plugin.js
CHANGED
|
@@ -63,11 +63,16 @@ function findBalanced(code, openChar, closeChar, startIdx) {
|
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
65
65
|
* 计算项目相对路径(用于 action ID 生成)。
|
|
66
|
+
*
|
|
67
|
+
* **自己负责去掉 query 与虚拟前缀**:调用方可能传原始 id(`Page.vue?vue&type=script&lang.ts`),
|
|
68
|
+
* 带 query 算出的 id 与不带 query 的不是同一个 —— 客户端 stub 与 服务端注册因此会对不上。
|
|
69
|
+
* 插件入口已经规范化过一次,这里再兜一次,让这两个变换函数单独用也正确。
|
|
66
70
|
*/
|
|
67
71
|
function toProjectRelative(filePath, root) {
|
|
68
|
-
|
|
72
|
+
const cleanPath = filePath.split("?")[0].replace(/^\0/, "");
|
|
73
|
+
let rel = cleanPath;
|
|
69
74
|
if (root) try {
|
|
70
|
-
rel = relative(root,
|
|
75
|
+
rel = relative(root, cleanPath);
|
|
71
76
|
} catch {}
|
|
72
77
|
return rel.replace(/\\/g, "/");
|
|
73
78
|
}
|
|
@@ -353,8 +358,51 @@ function transformActionsForClient(code, filePath, root) {
|
|
|
353
358
|
const replacement = `__ubean_createActionStub(${JSON.stringify(id)})`;
|
|
354
359
|
result = result.slice(0, call.start) + replacement + result.slice(call.end + 1);
|
|
355
360
|
}
|
|
361
|
+
result = stripUnusedSpecifiers(result, [
|
|
362
|
+
"defineAction",
|
|
363
|
+
"fail",
|
|
364
|
+
"ActionError",
|
|
365
|
+
"defineServerFn"
|
|
366
|
+
]);
|
|
356
367
|
const importStmt = `import { createActionStub as __ubean_createActionStub } from '@ubean/routes/runtime';\n`;
|
|
357
|
-
if (!result.includes("@ubean/routes/runtime'")) result = importStmt
|
|
368
|
+
if (!result.includes("@ubean/routes/runtime'")) result = injectImport(result, importStmt);
|
|
369
|
+
return result;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* 注入 import:JS/TS 放到文件顶部;**SFC 放到 `<script>` 块内**。
|
|
373
|
+
*
|
|
374
|
+
* 必须是块内 —— `@vitejs/plugin-vue` 会把 script 块的 import 提升进它编译出的主模块,放在 SFC
|
|
375
|
+
* 顶部(`<script>` 之前)会直接变成非法 SFC。这也是「转换必须落在主模块而不是 `?type=script`
|
|
376
|
+
* 子请求」的原因:主模块才是 Vue 真正编译的那份(脚本子请求的转换结果不会被使用)。
|
|
377
|
+
*/
|
|
378
|
+
function injectImport(code, importStmt) {
|
|
379
|
+
if (!code.trimStart().startsWith("<")) return importStmt + code;
|
|
380
|
+
const scriptTag = /<script\b[^>]*>/.exec(code);
|
|
381
|
+
if (!scriptTag) return importStmt + code;
|
|
382
|
+
const insertAt = scriptTag.index + scriptTag[0].length;
|
|
383
|
+
return `${code.slice(0, insertAt)}\n${importStmt}${code.slice(insertAt)}`;
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* 删除已无引用的具名 import 说明符(并清理空掉的 import 语句)。
|
|
387
|
+
*
|
|
388
|
+
* 只处理「命名导入 + from '…'」这一种形态(框架约定:服务端 API 从 `ubean/server` 等入口具名导入)。
|
|
389
|
+
* 判定用「删除 import 语句后名字是否还出现」——够用且不引入解析器依赖;名字出现在字符串/注释里
|
|
390
|
+
* 时会保守地保留该说明符(保留是安全的,删除才危险)。
|
|
391
|
+
*/
|
|
392
|
+
function stripUnusedSpecifiers(code, names) {
|
|
393
|
+
let result = code;
|
|
394
|
+
for (const name of new Set(names)) {
|
|
395
|
+
const match = new RegExp(`^import\\s*\\{([^}]*)\\}\\s*from\\s*(['"][^'"]+['"]);?[ \\t]*$`, "m").exec(result);
|
|
396
|
+
if (!match) continue;
|
|
397
|
+
const specifiers = match[1].split(",").map((part) => part.trim()).filter(Boolean);
|
|
398
|
+
const target = specifiers.find((spec) => spec === name || spec === `${name} as ${name}`);
|
|
399
|
+
if (!target) continue;
|
|
400
|
+
const withoutImport = result.replace(match[0], "");
|
|
401
|
+
if (new RegExp(`\\b${name}\\b`).test(withoutImport)) continue;
|
|
402
|
+
const remaining = specifiers.filter((spec) => spec !== target);
|
|
403
|
+
const replacement = remaining.length > 0 ? `import { ${remaining.join(", ")} } from ${match[2]};` : "";
|
|
404
|
+
result = result.replace(match[0], replacement);
|
|
405
|
+
}
|
|
358
406
|
return result;
|
|
359
407
|
}
|
|
360
408
|
/**
|
|
@@ -370,13 +418,14 @@ function ubeanServerActionsPlugin(options = {}) {
|
|
|
370
418
|
enforce: "pre",
|
|
371
419
|
transform(code, id, transformOptions) {
|
|
372
420
|
if (id.includes("/node_modules/") || id.includes("\0")) return null;
|
|
373
|
-
|
|
421
|
+
const [filePath, query = ""] = id.split("?");
|
|
422
|
+
if (!(filePath.endsWith(".vue") && (!query || /(^|&)(vue|type=script)(&|$)/.test(query))) && !/\.(ts|js|mts|mjs|tsx|jsx)$/.test(filePath)) return null;
|
|
374
423
|
if (!hasDefineActionCall(code)) return null;
|
|
375
424
|
if (transformOptions?.ssr === true) {
|
|
376
|
-
const transformed = transformActionsForServer(code,
|
|
425
|
+
const transformed = transformActionsForServer(code, filePath, root);
|
|
377
426
|
return transformed ? { code: transformed } : null;
|
|
378
427
|
}
|
|
379
|
-
const transformed = transformActionsForClient(code,
|
|
428
|
+
const transformed = transformActionsForClient(code, filePath, root);
|
|
380
429
|
return transformed ? { code: transformed } : null;
|
|
381
430
|
}
|
|
382
431
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as VirtualModuleTransform, c as defineVirtualModulePrefix, i as VirtualModuleResolver, l as resetVirtualRegistry, n as VirtualModuleContext, o as createVirtualRegistry, r as VirtualModuleRegistry, s as defineVirtualModule, t as VirtualModule, u as useVirtualRegistry } from "./virtual-registry-CaU8k-YP.js";
|
|
2
2
|
import { CompiledLayout, CompiledMiddleware, CompiledPage, CompiledRoute } from "@ubean/routes";
|
|
3
3
|
import { ScannedApiRoute, ScannedLocale, ScannedMiddleware, ScannedPageRoute } from "@ubean/scan";
|
|
4
4
|
//#region src/macros.d.ts
|
|
@@ -96,4 +96,4 @@ export declare function createMetaVirtualModule(): VirtualModule;
|
|
|
96
96
|
export declare function createAppVirtualModule(apiRoutes: ScannedApiRoute[], middlewares: ScannedMiddleware[], pages: ScannedPageRoute[], srcDir: string): VirtualModule;
|
|
97
97
|
export declare function createLocalesVirtualModule(_locales: ScannedLocale[], defaultLocale: string | undefined, srcDir?: string, i18nConfigJson?: string): VirtualModule;
|
|
98
98
|
//#endregion
|
|
99
|
-
export { type VirtualModule, type VirtualModuleContext, VirtualModuleRegistry, type VirtualModuleTransform, defineVirtualModule, defineVirtualModulePrefix, resetVirtualRegistry, useVirtualRegistry };
|
|
99
|
+
export { type VirtualModule, type VirtualModuleContext, VirtualModuleRegistry, type VirtualModuleResolver, type VirtualModuleTransform, createVirtualRegistry, defineVirtualModule, defineVirtualModulePrefix, resetVirtualRegistry, useVirtualRegistry };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
import { a as createRoutingVirtualModule, i as createPagesVirtualModule, n as createLocalesVirtualModule, o as stripMacros, r as createMetaVirtualModule, s as transformMacros, t as createAppVirtualModule } from "./virtual-modules-
|
|
3
|
-
|
|
4
|
-
export { SSR_SINGLETON_DEDUPE, SSR_SINGLETON_OPTIMIZE_EXCLUDE, SSR_SINGLETON_PACKAGES, VirtualModuleRegistry, createAppVirtualModule, createLocalesVirtualModule, createMetaVirtualModule, createPagesVirtualModule, createRoutingVirtualModule, defineVirtualModule, defineVirtualModulePrefix, getComponentResolvers, getCssImports, registerComponentResolver, registerCssImport, resetModuleRegistry, resetVirtualRegistry, ssrSingletonDevPolicy, ssrSingletonProdOptimizeExclude, ssrSingletonProdSsr, stripMacros, transformMacros, useVirtualRegistry };
|
|
1
|
+
import { _ as resetVirtualRegistry, a as ssrSingletonProdOptimizeExclude, c as getComponentResolvers, d as registerCssImport, f as resetModuleRegistry, g as defineVirtualModulePrefix, h as defineVirtualModule, i as ssrSingletonDevPolicy, l as getCssImports, m as createVirtualRegistry, n as SSR_SINGLETON_OPTIMIZE_EXCLUDE, o as ssrSingletonProdSsr, p as VirtualModuleRegistry, r as SSR_SINGLETON_PACKAGES, t as SSR_SINGLETON_DEDUPE, u as registerComponentResolver, v as useVirtualRegistry } from "./ssr-singleton-DPTawJSx.js";
|
|
2
|
+
import { a as createRoutingVirtualModule, i as createPagesVirtualModule, n as createLocalesVirtualModule, o as stripMacros, r as createMetaVirtualModule, s as transformMacros, t as createAppVirtualModule } from "./virtual-modules-CvGWlsXj.js";
|
|
3
|
+
export { SSR_SINGLETON_DEDUPE, SSR_SINGLETON_OPTIMIZE_EXCLUDE, SSR_SINGLETON_PACKAGES, VirtualModuleRegistry, createAppVirtualModule, createLocalesVirtualModule, createMetaVirtualModule, createPagesVirtualModule, createRoutingVirtualModule, createVirtualRegistry, defineVirtualModule, defineVirtualModulePrefix, getComponentResolvers, getCssImports, registerComponentResolver, registerCssImport, resetModuleRegistry, resetVirtualRegistry, ssrSingletonDevPolicy, ssrSingletonProdOptimizeExclude, ssrSingletonProdSsr, stripMacros, transformMacros, useVirtualRegistry };
|
package/dist/prerender.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PrerenderConfig, PrerenderResult, RouteRule } from "@ubean/config";
|
|
1
|
+
import { PrerenderConfig, PrerenderResult, ResolvedPrerenderConfig, RouteRule } from "@ubean/config";
|
|
2
2
|
import { ScannedPageRoute } from "@ubean/scan";
|
|
3
3
|
import { RouteRule as RouteRule$1 } from "@ubean/shared";
|
|
4
4
|
//#region src/prerender.d.ts
|
|
@@ -128,6 +128,18 @@ export interface ExtractedPayload {
|
|
|
128
128
|
*/
|
|
129
129
|
export declare function extractDataPayload(html: string, route: string): ExtractedPayload | null;
|
|
130
130
|
export declare function writePrerenderedFile(filePath: string, html: string): Promise<void>;
|
|
131
|
+
/**
|
|
132
|
+
* 预渲染产物的落盘目录(**唯一**计算处,`prerender()` 与搜索索引共用)。
|
|
133
|
+
*
|
|
134
|
+
* 优先用显式配置的 `prerender.staticDir`;未配置时从**本次构建的** `build.outputDir` 派生为
|
|
135
|
+
* `<outputDir>/public`。
|
|
136
|
+
*
|
|
137
|
+
* 为什么不能给 `staticDir` 一个写死的默认值(曾经是 `'dist/public'`):`build.outputDir` 会被
|
|
138
|
+
* preset(`dist/aws` 等)与 `--outDir` 改动,而写死的默认值不跟着动 —— 实测 `ubean build --outDir
|
|
139
|
+
* .temp-x` 的客户端产物落在 `.temp-x/public`,预渲染 HTML 却写进了 `dist/public`:产物被劈成两
|
|
140
|
+
* 半,且失败是静默的(两边都不报错,只有产物树里少文件)。
|
|
141
|
+
*/
|
|
142
|
+
export declare function resolvePrerenderStaticDir(cwd: string, buildOutputDir: string, prerenderConfig: Pick<ResolvedPrerenderConfig, 'staticDir'>): string;
|
|
131
143
|
export declare function prerender(options: PrerendererOptions): Promise<PrerenderResult>;
|
|
132
144
|
export declare function generatePrerenderManifest(result: PrerenderResult, baseUrl?: string): {
|
|
133
145
|
routes: string[];
|
package/dist/prerender.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { STATIC_NOT_FOUND_ROUTE } from "./static-render.js";
|
|
2
|
-
import { dirname, join } from "pathe";
|
|
2
|
+
import { dirname, isAbsolute, join } from "pathe";
|
|
3
3
|
import { resolvePrerenderConfig } from "@ubean/config";
|
|
4
|
-
import { DATA_PAYLOAD_ID } from "@ubean/pages";
|
|
5
4
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
5
|
+
import { DATA_PAYLOAD_ID } from "@ubean/pages";
|
|
6
6
|
import { matchGlob } from "@ubean/shared";
|
|
7
7
|
//#region src/prerender.ts
|
|
8
8
|
const LINK_REGEX = /<a[^>]+href=["']([^"']+)["'][^>]*>/gi;
|
|
@@ -196,6 +196,21 @@ const _logger = {
|
|
|
196
196
|
success: (msg) => console.log(msg),
|
|
197
197
|
debug: (_msg) => {}
|
|
198
198
|
};
|
|
199
|
+
/**
|
|
200
|
+
* 预渲染产物的落盘目录(**唯一**计算处,`prerender()` 与搜索索引共用)。
|
|
201
|
+
*
|
|
202
|
+
* 优先用显式配置的 `prerender.staticDir`;未配置时从**本次构建的** `build.outputDir` 派生为
|
|
203
|
+
* `<outputDir>/public`。
|
|
204
|
+
*
|
|
205
|
+
* 为什么不能给 `staticDir` 一个写死的默认值(曾经是 `'dist/public'`):`build.outputDir` 会被
|
|
206
|
+
* preset(`dist/aws` 等)与 `--outDir` 改动,而写死的默认值不跟着动 —— 实测 `ubean build --outDir
|
|
207
|
+
* .temp-x` 的客户端产物落在 `.temp-x/public`,预渲染 HTML 却写进了 `dist/public`:产物被劈成两
|
|
208
|
+
* 半,且失败是静默的(两边都不报错,只有产物树里少文件)。
|
|
209
|
+
*/
|
|
210
|
+
function resolvePrerenderStaticDir(cwd, buildOutputDir, prerenderConfig) {
|
|
211
|
+
if (prerenderConfig.staticDir) return isAbsolute(prerenderConfig.staticDir) ? prerenderConfig.staticDir : join(cwd, prerenderConfig.staticDir);
|
|
212
|
+
return isAbsolute(buildOutputDir) ? join(buildOutputDir, "public") : join(cwd, buildOutputDir, "public");
|
|
213
|
+
}
|
|
199
214
|
async function prerender(options) {
|
|
200
215
|
const startTime = Date.now();
|
|
201
216
|
const config = resolvePrerenderConfig(options.prerender);
|
|
@@ -207,7 +222,7 @@ async function prerender(options) {
|
|
|
207
222
|
skipped: [],
|
|
208
223
|
duration: 0
|
|
209
224
|
};
|
|
210
|
-
const outputDir =
|
|
225
|
+
const outputDir = resolvePrerenderStaticDir(options.cwd, options.outputDir, config);
|
|
211
226
|
const { routes: initialRoutes, skipped: initiallySkipped } = collectPrerenderRoutes(options.pages, {
|
|
212
227
|
all: config.all,
|
|
213
228
|
include: config.include,
|
|
@@ -309,4 +324,4 @@ function generatePrerenderManifest(result, baseUrl = "/") {
|
|
|
309
324
|
};
|
|
310
325
|
}
|
|
311
326
|
//#endregion
|
|
312
|
-
export { collectPrerenderRoutes, extractDataPayload, extractLinks, extractPrerenderRoutesFromRules, generatePrerenderManifest, prerender, routeToDataFilePath, routeToFilePath, writePrerenderedFile };
|
|
327
|
+
export { collectPrerenderRoutes, extractDataPayload, extractLinks, extractPrerenderRoutesFromRules, generatePrerenderManifest, prerender, resolvePrerenderStaticDir, routeToDataFilePath, routeToFilePath, writePrerenderedFile };
|
package/dist/production.d.ts
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
|
+
import { r as VirtualModuleRegistry } from "./virtual-registry-CaU8k-YP.js";
|
|
1
2
|
import { ResolvedConfig } from "@ubean/config";
|
|
2
|
-
import { ScanResult } from "@ubean/scan";
|
|
3
3
|
import { Preset } from "@ubean/preset";
|
|
4
|
+
import { ScanResult } from "@ubean/scan";
|
|
5
|
+
import { Plugin } from "vite";
|
|
6
|
+
//#region src/vite/build-app.d.ts
|
|
7
|
+
/**
|
|
8
|
+
* 一次 `createBuilder` 完成整套生产构建(`ubean build` 与 `vite build` 共用的唯一编排)。
|
|
9
|
+
*
|
|
10
|
+
* **驱动权声明**:本函数自己就是编排者,因此先在环境里声明「构建由调用方驱动」,让插件侧的
|
|
11
|
+
* `config` 钩子**不要**再注册它自己的 `builder.buildApp` —— 否则同一个 config 的 `builder` 字段
|
|
12
|
+
* 会被插件返回值合并掉,本函数的内联编排不再执行、`manifest` 保持 undefined,表现为**静默返回
|
|
13
|
+
* undefined**(RM-V36 把开关默认打开后由 `build-parity.test.ts` 实测撞到)。与 CLI 用的是同一个
|
|
14
|
+
* 环境变量,结束后还原,避免影响同进程内的其它调用。
|
|
15
|
+
*/
|
|
16
|
+
export declare function buildWithEnvironments(options: BuildOptions): Promise<BuildManifest>;
|
|
17
|
+
//#endregion
|
|
4
18
|
//#region src/production.d.ts
|
|
5
19
|
export interface BuildOptions {
|
|
6
20
|
cwd: string;
|
|
@@ -24,5 +38,47 @@ export interface BuildManifest {
|
|
|
24
38
|
serverDir: string;
|
|
25
39
|
preset: string;
|
|
26
40
|
}
|
|
27
|
-
|
|
41
|
+
/**
|
|
42
|
+
* 把扫描到的页面序列化进服务端入口(`const _pages = [...]`)。
|
|
43
|
+
*
|
|
44
|
+
* **白名单必须覆盖语义字段**:此前只序列化了 `relativePath/name/route/layout/reuseTarget/isReuse/
|
|
45
|
+
* pageMeta`,于是 `matchers` / `slot` **在生产构建里丢失** ——
|
|
46
|
+
* dev 用扫描得到的活对象(`enhanceDevApp` / `buildDevSsrRoutes` 直接拿 `scanResult.pages`),所以本地
|
|
47
|
+
* 一切正常,只有构建产物坏掉:带着 `[id=numeric]` 的路由在 dev 返回 404、在生产返回 200(实测)。
|
|
48
|
+
* 这类「dev 正常、产物丢失元数据」的缺陷对用户最不友好,因此单独抽成函数并配单测
|
|
49
|
+
* (`packages/builder/test/page-metadata.test.ts`)。
|
|
50
|
+
*
|
|
51
|
+
* 不含 `fullPath`/`dirname`/`basename`(构建机上的文件系统细节,产物不需要)与 `frontmatter`
|
|
52
|
+
* (Markdown 页正文用,服务端路由不消费)。拦截路由的两个字段(`interceptFrom` /
|
|
53
|
+
* `interceptTarget`)曾在这份白名单里,随该约定一起移除([docs/adr/0010] 刻意不做)。
|
|
54
|
+
*/
|
|
55
|
+
export declare function serializePagesForEntry(pages: ScanResult['pages']): string;
|
|
56
|
+
export declare function generateVirtualModulesToDisk(cwd: string, config: ResolvedConfig, scanResult: ScanResult, virtualDir: string, preset: Preset, registry: VirtualModuleRegistry, contentSnapshot?: Record<string, unknown[]>): Promise<string>;
|
|
57
|
+
export type PresetBuildConfig = ReturnType<typeof getPresetBuildConfig>;
|
|
58
|
+
export declare function getPresetBuildConfig(preset: Preset): {
|
|
59
|
+
format: "esm";
|
|
60
|
+
target: string;
|
|
61
|
+
entryType: "node";
|
|
62
|
+
external: (string | RegExp)[];
|
|
63
|
+
} | {
|
|
64
|
+
format: "esm";
|
|
65
|
+
target: string;
|
|
66
|
+
entryType: "worker";
|
|
67
|
+
external: (string | RegExp)[];
|
|
68
|
+
} | {
|
|
69
|
+
format: "esm";
|
|
70
|
+
target: string;
|
|
71
|
+
entryType: "fetch";
|
|
72
|
+
external: (string | RegExp)[];
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* SSR 期的 islands 注册表空壳插件。
|
|
76
|
+
*
|
|
77
|
+
* 真正的注册表由 `ubeanIslandsPlugin` 在**客户端**构建期填充;SSR 期 islands 由服务端渲染
|
|
78
|
+
* (不水合),空壳即可 —— 但不能让它以裸 `virtual:ubean-islands-registry` 泄漏给 Node。
|
|
79
|
+
*/
|
|
80
|
+
export declare function createIslandsSsrStubPlugin(): Plugin;
|
|
81
|
+
export declare function generateNodeServerEntry(): string;
|
|
82
|
+
export declare function generateStandardHandlerEntry(): string;
|
|
83
|
+
export declare function generateCloudflareWorkerEntry(): string;
|
|
28
84
|
//#endregion
|