@ubean/ssr 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.
- package/dist/index.d.ts +32 -0
- package/dist/index.js +99 -0
- package/package.json +4 -4
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Component } from "vue";
|
|
2
|
+
import { renderToString } from "@vue/server-renderer";
|
|
3
|
+
import { PageRenderer } from "@ubean/pages";
|
|
4
|
+
import { ResolvedAppConfig } from "@ubean/runtime/define-app";
|
|
5
|
+
import { RouteRecordRaw } from "vue-router";
|
|
6
|
+
//#region src/index.d.ts
|
|
7
|
+
interface VueRendererSimpleOptions {
|
|
8
|
+
resolvePageComponent: (path: string) => Promise<Component | null>;
|
|
9
|
+
resolveLayoutComponent: (name: string | false | null | undefined) => Promise<Component | null>;
|
|
10
|
+
defaultLayout?: string | null;
|
|
11
|
+
/**
|
|
12
|
+
* Resolves the user's `defineApp` config for the server side.
|
|
13
|
+
* When provided, plugins / globalComponents / provides / head / onAppCreated
|
|
14
|
+
* will be applied to each SSR app instance.
|
|
15
|
+
*/
|
|
16
|
+
resolveAppConfig?: () => ResolvedAppConfig | Promise<ResolvedAppConfig>;
|
|
17
|
+
}
|
|
18
|
+
interface VueRendererRouterOptions {
|
|
19
|
+
routes: RouteRecordRaw[];
|
|
20
|
+
resolveLayoutComponent: (name: string | false | null | undefined) => Promise<Component | null>;
|
|
21
|
+
defaultLayout?: string | null;
|
|
22
|
+
/**
|
|
23
|
+
* Resolves the user's `defineApp` config for the server side.
|
|
24
|
+
* When provided, plugins / globalComponents / provides / head / onAppCreated
|
|
25
|
+
* will be applied to each SSR app instance.
|
|
26
|
+
*/
|
|
27
|
+
resolveAppConfig?: () => ResolvedAppConfig | Promise<ResolvedAppConfig>;
|
|
28
|
+
}
|
|
29
|
+
type VueRendererOptions = VueRendererSimpleOptions | VueRendererRouterOptions;
|
|
30
|
+
declare function createVueRenderer(options: VueRendererOptions): PageRenderer;
|
|
31
|
+
//#endregion
|
|
32
|
+
export { VueRendererOptions, VueRendererRouterOptions, VueRendererSimpleOptions, createVueRenderer, renderToString };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { createSSRApp, defineComponent, h, provide, reactive } from "vue";
|
|
2
|
+
import { renderToString, renderToString as renderToString$1 } from "@vue/server-renderer";
|
|
3
|
+
import { getIslandsBootstrapScript } from "@ubean/islands";
|
|
4
|
+
import { SSR_CONTENT_MARKER } from "@ubean/pages";
|
|
5
|
+
import { applyAppConfig } from "@ubean/runtime/define-app";
|
|
6
|
+
import { createHead, transformHtmlTemplate } from "@unhead/vue/server";
|
|
7
|
+
//#region src/index.ts
|
|
8
|
+
/**
|
|
9
|
+
* Push a `PageHead` (from `defineApp` or page-level `head`) into an @unhead head instance.
|
|
10
|
+
* Extracted so both the global app head and per-page head use the same mapping.
|
|
11
|
+
*/
|
|
12
|
+
function pushPageHead(head, pageHead) {
|
|
13
|
+
const headInput = {};
|
|
14
|
+
if (pageHead.title) headInput.title = pageHead.title;
|
|
15
|
+
if (pageHead.htmlAttrs) headInput.htmlAttrs = pageHead.htmlAttrs;
|
|
16
|
+
if (pageHead.bodyAttrs) headInput.bodyAttrs = pageHead.bodyAttrs;
|
|
17
|
+
if (pageHead.meta) headInput.meta = pageHead.meta;
|
|
18
|
+
if (pageHead.link) headInput.link = pageHead.link;
|
|
19
|
+
if (pageHead.script) headInput.script = pageHead.script;
|
|
20
|
+
head.push(headInput);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Apply user's `defineApp` config (plugins, globalComponents, provides) and
|
|
24
|
+
* invoke `onAppCreated` on a freshly created SSR app instance.
|
|
25
|
+
*/
|
|
26
|
+
async function applyServerAppConfig(app, appConfig) {
|
|
27
|
+
applyAppConfig(app, appConfig, "server");
|
|
28
|
+
if (appConfig.onAppCreated) await appConfig.onAppCreated(app);
|
|
29
|
+
}
|
|
30
|
+
function isSimpleOptions(opts) {
|
|
31
|
+
return "resolvePageComponent" in opts;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Resolve a single layout component by name.
|
|
35
|
+
* Returns `null` when layout is `false`, `null`, or not found.
|
|
36
|
+
* ubean uses flat single-layer layout (no nesting), matching the
|
|
37
|
+
* `layout: string | false` field on each page route.
|
|
38
|
+
*/
|
|
39
|
+
async function resolveSingleLayout(layoutName, defaultLayout, resolveLayoutComponent) {
|
|
40
|
+
const resolved = layoutName === void 0 ? defaultLayout : layoutName;
|
|
41
|
+
if (resolved === false || resolved == null) return null;
|
|
42
|
+
return resolveLayoutComponent(resolved);
|
|
43
|
+
}
|
|
44
|
+
function createSimpleApp(pageObj, PageComp, layout, head) {
|
|
45
|
+
const pageData = reactive({ ...pageObj });
|
|
46
|
+
const PAGE_KEY = Symbol("ubean-page");
|
|
47
|
+
const app = createSSRApp(defineComponent({
|
|
48
|
+
name: "UbeanSimpleApp",
|
|
49
|
+
setup() {
|
|
50
|
+
provide(PAGE_KEY, pageData);
|
|
51
|
+
return () => {
|
|
52
|
+
const inner = h(PageComp, pageObj.props || {});
|
|
53
|
+
if (!layout) return inner;
|
|
54
|
+
return h(layout, {}, { default: () => inner });
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}));
|
|
58
|
+
app.use(head);
|
|
59
|
+
return app;
|
|
60
|
+
}
|
|
61
|
+
function createVueRenderer(options) {
|
|
62
|
+
const render = async (pageObj, shellHtml, _assetTags, renderContext) => {
|
|
63
|
+
const head = createHead();
|
|
64
|
+
const appConfig = options.resolveAppConfig ? await options.resolveAppConfig() : null;
|
|
65
|
+
if (appConfig?.head) pushPageHead(head, appConfig.head);
|
|
66
|
+
if (renderContext?.locale) head.push({ htmlAttrs: {
|
|
67
|
+
lang: renderContext.locale,
|
|
68
|
+
dir: renderContext.localeDir || "ltr"
|
|
69
|
+
} });
|
|
70
|
+
if (pageObj.head) pushPageHead(head, pageObj.head);
|
|
71
|
+
let appHtml;
|
|
72
|
+
if (isSimpleOptions(options)) {
|
|
73
|
+
const pageComponent = await options.resolvePageComponent(pageObj.component);
|
|
74
|
+
if (!pageComponent) throw new Error(`[ubean] Could not resolve page component: ${pageObj.component}`);
|
|
75
|
+
const app = createSimpleApp(pageObj, pageComponent, pageObj.layout === false ? null : await resolveSingleLayout(pageObj.layout, options.defaultLayout || null, options.resolveLayoutComponent), head);
|
|
76
|
+
if (appConfig) await applyServerAppConfig(app, appConfig);
|
|
77
|
+
appHtml = await renderToString$1(app);
|
|
78
|
+
} else {
|
|
79
|
+
const { createUbeanSSRApp } = await import("@ubean/runtime/app");
|
|
80
|
+
const { app: createdApp, router } = createUbeanSSRApp(pageObj, {
|
|
81
|
+
routes: options.routes,
|
|
82
|
+
resolveLayoutComponent: options.resolveLayoutComponent,
|
|
83
|
+
defaultLayout: options.defaultLayout,
|
|
84
|
+
head
|
|
85
|
+
});
|
|
86
|
+
if (appConfig) await applyServerAppConfig(createdApp, appConfig);
|
|
87
|
+
await router.isReady();
|
|
88
|
+
appHtml = await renderToString$1(createdApp);
|
|
89
|
+
}
|
|
90
|
+
if (!shellHtml) return appHtml;
|
|
91
|
+
return transformHtmlTemplate(head, shellHtml.replace(SSR_CONTENT_MARKER, appHtml));
|
|
92
|
+
};
|
|
93
|
+
return {
|
|
94
|
+
render,
|
|
95
|
+
preambleScript: getIslandsBootstrapScript()
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
//#endregion
|
|
99
|
+
export { createVueRenderer, renderToString };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ubean/ssr",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Vue SSR renderer for ubean (createVueRenderer, renderToString, applyServerAppConfig)",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
"@vue/server-renderer": "^3.5.40",
|
|
21
21
|
"vue": "^3.5.40",
|
|
22
22
|
"vue-router": "^5.2.0",
|
|
23
|
-
"@ubean/
|
|
24
|
-
"@ubean/
|
|
25
|
-
"@ubean/pages": "0.1.
|
|
23
|
+
"@ubean/runtime": "0.1.3",
|
|
24
|
+
"@ubean/islands": "0.1.3",
|
|
25
|
+
"@ubean/pages": "0.1.3"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/node": "^26.1.1",
|