@bagelink/blox 1.12.22 → 1.12.23
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/CmsPageView.vue.d.ts.map +1 -1
- package/dist/PreviewApp-C2T03Jm9.cjs +4 -0
- package/dist/PreviewApp-CmThrLvv.js +4 -0
- package/dist/PreviewApp.vue.d.ts.map +1 -1
- package/dist/PreviewApp.vue_vue_type_style_index_0_lang-B0N5QbfS.js +157 -0
- package/dist/PreviewApp.vue_vue_type_style_index_0_lang-BTuE4GmT.cjs +156 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/bridge.d.ts +1 -0
- package/dist/bridge.d.ts.map +1 -1
- package/dist/core-C3Iu5qa2.js +460 -0
- package/dist/core-_fnHoEZN.cjs +459 -0
- package/dist/core.d.ts.map +1 -1
- package/dist/createBloxApp.d.ts +107 -0
- package/dist/createBloxApp.d.ts.map +1 -0
- package/dist/defineBlock.d.ts +2 -0
- package/dist/defineBlock.d.ts.map +1 -1
- package/dist/index.cjs +79 -585
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +78 -583
- package/dist/{prerender-6jE_obPj.cjs → prerender-Bi7YtzSp.cjs} +246 -6
- package/dist/prerender-D3Q4jKXm.js +522 -0
- package/dist/schema.d.ts +2 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/ssg/cli.cjs +48 -5
- package/dist/ssg/cli.mjs +48 -5
- package/dist/ssg/client.cjs +50 -3
- package/dist/ssg/client.d.ts +2 -1
- package/dist/ssg/client.d.ts.map +1 -1
- package/dist/ssg/client.mjs +49 -2
- package/dist/ssg/cms-routes.d.ts +21 -4
- package/dist/ssg/cms-routes.d.ts.map +1 -1
- package/dist/ssg/collection-cache.d.ts +53 -0
- package/dist/ssg/collection-cache.d.ts.map +1 -0
- package/dist/ssg/constants.d.ts +4 -0
- package/dist/ssg/constants.d.ts.map +1 -1
- package/dist/ssg/createSSREntry.d.ts +73 -0
- package/dist/ssg/createSSREntry.d.ts.map +1 -0
- package/dist/ssg/index.cjs +138 -6
- package/dist/ssg/index.d.ts +10 -3
- package/dist/ssg/index.d.ts.map +1 -1
- package/dist/ssg/index.mjs +124 -12
- package/dist/ssg/prerender.d.ts +19 -1
- package/dist/ssg/prerender.d.ts.map +1 -1
- package/dist/ssg/render-resolved-page.d.ts +13 -3
- package/dist/ssg/render-resolved-page.d.ts.map +1 -1
- package/dist/ssg/seo.d.ts +66 -0
- package/dist/ssg/seo.d.ts.map +1 -0
- package/dist/style.css +20 -0
- package/dist/vite-plugin.cjs +142 -3
- package/dist/vite-plugin.d.ts +22 -21
- package/dist/vite-plugin.d.ts.map +1 -1
- package/dist/vite-plugin.mjs +142 -3
- package/package.json +4 -1
- package/dist/PreviewApp-BZNzZkit.js +0 -4
- package/dist/PreviewApp-C1WvJWI4.cjs +0 -4
- package/dist/constants-BIbQhd3z.js +0 -4
- package/dist/constants-fZvybj0k.cjs +0 -3
- package/dist/prerender-DYmDaqcz.js +0 -282
package/dist/ssg/index.mjs
CHANGED
|
@@ -1,38 +1,150 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { b as buildPageHead } from "../prerender-D3Q4jKXm.js";
|
|
2
|
+
import { d, c, f, g, e, h, p, a } from "../prerender-D3Q4jKXm.js";
|
|
3
|
+
import { BLOX_STATE_WINDOW_KEY, BLOX_COLLECTIONS_WINDOW_KEY, BLOX_WEBSITE_ID_WINDOW_KEY } from "./client.mjs";
|
|
4
|
+
import { getCollectionCache, getEmbeddedWebsiteId, installBloxStateCache, installCollectionCache } from "./client.mjs";
|
|
5
|
+
import { createPinia } from "pinia";
|
|
6
|
+
import { createSSRApp, markRaw } from "vue";
|
|
7
|
+
import { c as createBlox } from "../core-C3Iu5qa2.js";
|
|
4
8
|
async function renderBloxSsgPage(options) {
|
|
5
9
|
const {
|
|
6
10
|
url,
|
|
7
11
|
resolvedData,
|
|
8
12
|
renderToString,
|
|
9
13
|
createAppForUrl,
|
|
10
|
-
stateWindowKey = BLOX_STATE_WINDOW_KEY
|
|
14
|
+
stateWindowKey = BLOX_STATE_WINDOW_KEY,
|
|
15
|
+
website = null,
|
|
16
|
+
websiteId = "",
|
|
17
|
+
collections
|
|
11
18
|
} = options;
|
|
12
|
-
const
|
|
13
|
-
const prevState =
|
|
19
|
+
const g2 = globalThis;
|
|
20
|
+
const prevState = g2[stateWindowKey];
|
|
14
21
|
if (resolvedData != null) {
|
|
15
|
-
|
|
22
|
+
g2[stateWindowKey] = { [url]: resolvedData };
|
|
16
23
|
}
|
|
17
24
|
try {
|
|
18
25
|
const { app, router } = createAppForUrl(url);
|
|
19
26
|
await router.push(url);
|
|
20
27
|
await router.isReady();
|
|
21
28
|
const html = await renderToString(app);
|
|
22
|
-
const
|
|
23
|
-
|
|
29
|
+
const stateScript = resolvedData != null ? `<script>window[${JSON.stringify(stateWindowKey)}]=${JSON.stringify({ [url]: resolvedData })};${"<"}/script>` : "";
|
|
30
|
+
const collectionsScript = collections && Object.keys(collections).length > 0 ? `<script>window[${JSON.stringify(BLOX_COLLECTIONS_WINDOW_KEY)}]=${JSON.stringify(collections)};${"<"}/script>` : "";
|
|
31
|
+
const websiteIdScript = websiteId ? `<script>window[${JSON.stringify(BLOX_WEBSITE_ID_WINDOW_KEY)}]=${JSON.stringify(websiteId)};${"<"}/script>` : "";
|
|
32
|
+
const head = buildPageHead({
|
|
33
|
+
url,
|
|
34
|
+
resolvedData,
|
|
35
|
+
website,
|
|
36
|
+
stateScript: [stateScript, collectionsScript, websiteIdScript].filter(Boolean).join("\n")
|
|
37
|
+
});
|
|
38
|
+
const lang = (website == null ? void 0 : website.default_locale) || "en";
|
|
39
|
+
const htmlAttrs = `lang="${lang}"`;
|
|
40
|
+
return { html, head, htmlAttrs };
|
|
24
41
|
} finally {
|
|
25
42
|
if (prevState !== void 0) {
|
|
26
|
-
|
|
43
|
+
g2[stateWindowKey] = prevState;
|
|
27
44
|
} else {
|
|
28
|
-
delete
|
|
45
|
+
delete g2[stateWindowKey];
|
|
29
46
|
}
|
|
30
47
|
}
|
|
31
48
|
}
|
|
49
|
+
let _websiteId = null;
|
|
50
|
+
function createBloxSSREntry(options) {
|
|
51
|
+
var _a;
|
|
52
|
+
const {
|
|
53
|
+
rootComponent,
|
|
54
|
+
createRouter,
|
|
55
|
+
modules,
|
|
56
|
+
websiteName,
|
|
57
|
+
store,
|
|
58
|
+
locale = "en",
|
|
59
|
+
supportedLocales = [locale],
|
|
60
|
+
plugins = [],
|
|
61
|
+
globalComponents = {}
|
|
62
|
+
} = options;
|
|
63
|
+
const apiBase = options.apiBase ?? (typeof process !== "undefined" ? (_a = process.env) == null ? void 0 : _a.BAGELINK_API_URL : void 0) ?? "https://api.bagel.to";
|
|
64
|
+
async function getWebsiteId() {
|
|
65
|
+
if (_websiteId) return _websiteId;
|
|
66
|
+
const res = await fetch(`${apiBase}/cms/websites`);
|
|
67
|
+
const data = await res.json();
|
|
68
|
+
const sites = Array.isArray(data) ? data : (data == null ? void 0 : data.data) ?? [];
|
|
69
|
+
const site = sites.find((s) => s.name === websiteName);
|
|
70
|
+
if (!(site == null ? void 0 : site.id)) throw new Error(`Website "${websiteName}" not found`);
|
|
71
|
+
_websiteId = site.id;
|
|
72
|
+
return _websiteId;
|
|
73
|
+
}
|
|
74
|
+
async function fetchResolvedPage(urlPath) {
|
|
75
|
+
const websiteId = await getWebsiteId();
|
|
76
|
+
const url = `${apiBase}/cms/websites/${websiteId}/resolve-path?path=${encodeURIComponent(urlPath)}&locale=${locale}`;
|
|
77
|
+
const res = await fetch(url);
|
|
78
|
+
if (!res.ok) throw new Error(`resolve-path ${res.status}: ${urlPath}`);
|
|
79
|
+
return res.json();
|
|
80
|
+
}
|
|
81
|
+
function buildApp(url) {
|
|
82
|
+
const router = createRouter("memory", url);
|
|
83
|
+
const app = createSSRApp(rootComponent);
|
|
84
|
+
const pinia = createPinia();
|
|
85
|
+
pinia.use(({ store: s }) => {
|
|
86
|
+
s.router = markRaw(router);
|
|
87
|
+
});
|
|
88
|
+
const blox = createBlox({
|
|
89
|
+
modules,
|
|
90
|
+
websiteName,
|
|
91
|
+
store,
|
|
92
|
+
defaultLocale: locale,
|
|
93
|
+
supportedLocales,
|
|
94
|
+
router
|
|
95
|
+
});
|
|
96
|
+
for (const plugin of plugins) {
|
|
97
|
+
if (Array.isArray(plugin)) {
|
|
98
|
+
const [p2, ...args] = plugin;
|
|
99
|
+
app.use(p2, ...args);
|
|
100
|
+
} else {
|
|
101
|
+
app.use(plugin);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
blox.install(app, {});
|
|
105
|
+
app.use(pinia);
|
|
106
|
+
app.use(router);
|
|
107
|
+
for (const [name, comp] of Object.entries(globalComponents)) {
|
|
108
|
+
app.component(name, comp);
|
|
109
|
+
}
|
|
110
|
+
return { app, router };
|
|
111
|
+
}
|
|
112
|
+
async function render(url, ctx) {
|
|
113
|
+
let resolvedData = null;
|
|
114
|
+
try {
|
|
115
|
+
resolvedData = await fetchResolvedPage(url);
|
|
116
|
+
} catch (e2) {
|
|
117
|
+
console.warn(`[prerender] Could not resolve: ${url} — ${e2.message}`);
|
|
118
|
+
}
|
|
119
|
+
const { renderToString } = await import("vue/server-renderer");
|
|
120
|
+
return renderBloxSsgPage({
|
|
121
|
+
url,
|
|
122
|
+
resolvedData,
|
|
123
|
+
renderToString,
|
|
124
|
+
createAppForUrl: buildApp,
|
|
125
|
+
website: ctx.website,
|
|
126
|
+
websiteId: ctx.websiteId,
|
|
127
|
+
collections: ctx.collections
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
return { render };
|
|
131
|
+
}
|
|
32
132
|
export {
|
|
133
|
+
BLOX_COLLECTIONS_WINDOW_KEY,
|
|
33
134
|
BLOX_STATE_WINDOW_KEY,
|
|
34
|
-
|
|
135
|
+
BLOX_WEBSITE_ID_WINDOW_KEY,
|
|
136
|
+
buildPageHead,
|
|
137
|
+
d as buildSiteHead,
|
|
138
|
+
createBloxSSREntry,
|
|
139
|
+
c as fetchCmsPrerenderPaths,
|
|
140
|
+
f as fetchCmsSiteData,
|
|
141
|
+
g as generateNetlifyRedirects,
|
|
142
|
+
e as generateRobotsTxt,
|
|
143
|
+
h as generateSitemapXml,
|
|
144
|
+
getCollectionCache,
|
|
145
|
+
getEmbeddedWebsiteId,
|
|
35
146
|
installBloxStateCache,
|
|
147
|
+
installCollectionCache,
|
|
36
148
|
p as polyfillBloxSsgGlobals,
|
|
37
149
|
a as prerender,
|
|
38
150
|
renderBloxSsgPage
|
package/dist/ssg/prerender.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { WebsiteRead } from '../api/types';
|
|
2
|
+
import { RedirectEntry } from './seo';
|
|
1
3
|
type ExcludeRule = string | RegExp | ((path: string) => boolean);
|
|
2
4
|
export interface PrerenderOptions {
|
|
3
5
|
root?: string;
|
|
@@ -9,10 +11,24 @@ export interface PrerenderOptions {
|
|
|
9
11
|
failFast?: boolean;
|
|
10
12
|
maxPages?: number;
|
|
11
13
|
mode?: 'dir' | 'file';
|
|
14
|
+
/** Website settings for SEO injection. */
|
|
15
|
+
website?: WebsiteRead | null;
|
|
16
|
+
/** Resolved website ID (embedded for client-side cache). */
|
|
17
|
+
websiteId?: string;
|
|
18
|
+
/** Redirects to write as _redirects (Netlify). */
|
|
19
|
+
redirects?: RedirectEntry[];
|
|
20
|
+
/** Pre-fetched datastore collections keyed by "store/collection". */
|
|
21
|
+
collections?: Record<string, unknown[]>;
|
|
12
22
|
}
|
|
13
23
|
export interface RenderContext {
|
|
14
24
|
manifest: Record<string, string[]> | null;
|
|
15
25
|
template: string;
|
|
26
|
+
/** Website settings passed through to the render function. */
|
|
27
|
+
website?: WebsiteRead | null;
|
|
28
|
+
/** Resolved website ID for client embedding. */
|
|
29
|
+
websiteId?: string;
|
|
30
|
+
/** Pre-fetched datastore collections keyed by "store/collection". */
|
|
31
|
+
collections?: Record<string, unknown[]>;
|
|
16
32
|
}
|
|
17
33
|
export interface RenderResult {
|
|
18
34
|
html: string;
|
|
@@ -38,7 +54,9 @@ export interface PrerenderResult {
|
|
|
38
54
|
* - "crawl" (default true) discovers internal links in rendered HTML and queues them.
|
|
39
55
|
* - excludePaths can be strings, RegExp, or a predicate function.
|
|
40
56
|
* - Route-level failures are logged and skipped by default.
|
|
57
|
+
* - Generates sitemap.xml, robots.txt, and _redirects post-render.
|
|
58
|
+
* - Strips hardcoded SEO tags from template and injects per-page equivalents.
|
|
41
59
|
*/
|
|
42
|
-
export declare function prerender({ root, clientOutDir, serverEntry, paths, crawl, excludePaths, failFast, maxPages, mode, }?: PrerenderOptions): Promise<PrerenderResult>;
|
|
60
|
+
export declare function prerender({ root, clientOutDir, serverEntry, paths, crawl, excludePaths, failFast, maxPages, mode, website, websiteId, redirects, collections, }?: PrerenderOptions): Promise<PrerenderResult>;
|
|
43
61
|
export {};
|
|
44
62
|
//# sourceMappingURL=prerender.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prerender.d.ts","sourceRoot":"","sources":["../../src/ssg/prerender.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"prerender.d.ts","sourceRoot":"","sources":["../../src/ssg/prerender.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAc1C,KAAK,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,CAAA;AAEhE,MAAM,WAAW,gBAAgB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,YAAY,CAAC,EAAE,WAAW,GAAG,WAAW,EAAE,CAAA;IAC1C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,IAAI,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;IACrB,0CAA0C;IAC1C,OAAO,CAAC,EAAE,WAAW,GAAG,IAAI,CAAA;IAC5B,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,kDAAkD;IAClD,SAAS,CAAC,EAAE,aAAa,EAAE,CAAA;IAC3B,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAA;CACvC;AAED,MAAM,WAAW,aAAa;IAC7B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,CAAA;IACzC,QAAQ,EAAE,MAAM,CAAA;IAChB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,WAAW,GAAG,IAAI,CAAA;IAC5B,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAA;CACvC;AAED,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,OAAO,CAAA;CACf;AAMD,MAAM,WAAW,eAAe;IAC/B,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;IAC7D,eAAe,EAAE,MAAM,CAAA;IACvB,eAAe,EAAE,MAAM,CAAA;CACvB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,SAAS,CAAC,EAC/B,IAAoB,EACpB,YAA4B,EAC5B,WAA0C,EAC1C,KAAU,EACV,KAAY,EACZ,YAAiB,EACjB,QAAgB,EAChB,QAAe,EACf,IAAY,EACZ,OAAc,EACd,SAAc,EACd,SAAc,EACd,WAAgB,GAChB,GAAE,gBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC,CA4HlD"}
|
|
@@ -1,16 +1,19 @@
|
|
|
1
|
+
import { WebsiteRead } from '../api/types';
|
|
1
2
|
export interface BloxSsgRouterLike {
|
|
2
3
|
push: (url: string) => Promise<void>;
|
|
3
4
|
isReady: () => Promise<void>;
|
|
4
5
|
}
|
|
5
6
|
/**
|
|
6
|
-
* Render a Blox CMS page to static HTML with embedded state.
|
|
7
|
+
* Render a Blox CMS page to static HTML with embedded state and full SEO head.
|
|
7
8
|
*
|
|
8
9
|
* Sets `globalThis.__BLOX_STATE__` *before* rendering so that
|
|
9
10
|
* `CmsPageView` can hydrate synchronously from the embedded data
|
|
10
11
|
* instead of waiting for an async fetch.
|
|
11
12
|
*
|
|
12
|
-
* Returns `{ html, head }` where
|
|
13
|
-
* `
|
|
13
|
+
* Returns `{ html, head, htmlAttrs }` where:
|
|
14
|
+
* - `head` contains per-page `<title>`, meta tags, OG, canonical, hreflang,
|
|
15
|
+
* plus the `<script>` that sets `window.__BLOX_STATE__`
|
|
16
|
+
* - `htmlAttrs` contains the `lang` attribute
|
|
14
17
|
*/
|
|
15
18
|
export declare function renderBloxSsgPage<TApp>(options: {
|
|
16
19
|
url: string;
|
|
@@ -21,8 +24,15 @@ export declare function renderBloxSsgPage<TApp>(options: {
|
|
|
21
24
|
router: BloxSsgRouterLike;
|
|
22
25
|
};
|
|
23
26
|
stateWindowKey?: string;
|
|
27
|
+
/** Website settings for SEO tags. If omitted, only state script is emitted. */
|
|
28
|
+
website?: WebsiteRead | null;
|
|
29
|
+
/** Resolved website ID — embedded so client skips GET /cms/websites. */
|
|
30
|
+
websiteId?: string;
|
|
31
|
+
/** Pre-fetched datastore collections — embedded for zero-fetch hydration. */
|
|
32
|
+
collections?: Record<string, unknown[]>;
|
|
24
33
|
}): Promise<{
|
|
25
34
|
html: string;
|
|
26
35
|
head?: string;
|
|
36
|
+
htmlAttrs?: string;
|
|
27
37
|
}>;
|
|
28
38
|
//# sourceMappingURL=render-resolved-page.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-resolved-page.d.ts","sourceRoot":"","sources":["../../src/ssg/render-resolved-page.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"render-resolved-page.d.ts","sourceRoot":"","sources":["../../src/ssg/render-resolved-page.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAK/C,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACpC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC5B;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE;IACtD,GAAG,EAAE,MAAM,CAAA;IACX,YAAY,EAAE,OAAO,GAAG,IAAI,CAAA;IAC5B,cAAc,EAAE,CAAC,GAAG,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IAC9C,eAAe,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK;QAAE,GAAG,EAAE,IAAI,CAAC;QAAC,MAAM,EAAE,iBAAiB,CAAA;KAAE,CAAA;IAC1E,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,+EAA+E;IAC/E,OAAO,CAAC,EAAE,WAAW,GAAG,IAAI,CAAA;IAC5B,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAA;CACvC,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA4D/D"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { PageRead, WebsiteRead } from '../api/types';
|
|
2
|
+
/** Resolved page data shape (subset of PageResolveRead). */
|
|
3
|
+
export interface SeoPageData {
|
|
4
|
+
page: PageRead;
|
|
5
|
+
alternates?: Record<string, string>;
|
|
6
|
+
contexts?: Record<string, Record<string, unknown> | null>;
|
|
7
|
+
}
|
|
8
|
+
/** Website meta bag (freeform JSON stored on WebsiteRead.meta). */
|
|
9
|
+
export interface WebsiteMeta {
|
|
10
|
+
default_meta_title?: string;
|
|
11
|
+
default_meta_description?: string;
|
|
12
|
+
default_og_image?: string;
|
|
13
|
+
webclip?: string;
|
|
14
|
+
og_site_name?: string;
|
|
15
|
+
og_description?: string;
|
|
16
|
+
og_type?: string;
|
|
17
|
+
twitter_card?: string;
|
|
18
|
+
twitter_site?: string;
|
|
19
|
+
canonical_base_url?: string;
|
|
20
|
+
noindex?: boolean;
|
|
21
|
+
verification_google?: string;
|
|
22
|
+
verification_bing?: string;
|
|
23
|
+
structured_data_org?: unknown;
|
|
24
|
+
[key: string]: unknown;
|
|
25
|
+
}
|
|
26
|
+
export interface RedirectEntry {
|
|
27
|
+
from_path: string;
|
|
28
|
+
to_path: string;
|
|
29
|
+
status_code: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Build a complete `<head>` fragment for a single page.
|
|
33
|
+
*
|
|
34
|
+
* Includes: title, meta description, OG tags, Twitter Card, canonical,
|
|
35
|
+
* hreflang alternates, noindex, and the __BLOX_STATE__ script.
|
|
36
|
+
*/
|
|
37
|
+
export declare function buildPageHead(options: {
|
|
38
|
+
url: string;
|
|
39
|
+
resolvedData: SeoPageData | null;
|
|
40
|
+
website: WebsiteRead | null;
|
|
41
|
+
stateScript?: string;
|
|
42
|
+
}): string;
|
|
43
|
+
/**
|
|
44
|
+
* Build site-wide `<head>` tags: verification, structured data, analytics, favicon.
|
|
45
|
+
* These replace hardcoded equivalents in the HTML template.
|
|
46
|
+
*/
|
|
47
|
+
export declare function buildSiteHead(website: WebsiteRead | null): string;
|
|
48
|
+
export declare function generateSitemapXml(options: {
|
|
49
|
+
renderedPaths: string[];
|
|
50
|
+
canonicalBase: string;
|
|
51
|
+
defaultChangefreq?: string;
|
|
52
|
+
defaultPriority?: string;
|
|
53
|
+
}): string;
|
|
54
|
+
export declare function generateRobotsTxt(options: {
|
|
55
|
+
robotsTxt?: string | null;
|
|
56
|
+
canonicalBase?: string;
|
|
57
|
+
noindex?: boolean;
|
|
58
|
+
}): string;
|
|
59
|
+
export declare function generateNetlifyRedirects(redirects: RedirectEntry[]): string;
|
|
60
|
+
/**
|
|
61
|
+
* Strip hardcoded SEO tags from the HTML template so SSG can inject
|
|
62
|
+
* per-page equivalents. Removes: title, meta description, og:*, twitter:*,
|
|
63
|
+
* apple-touch-icon, and favicon.
|
|
64
|
+
*/
|
|
65
|
+
export declare function stripTemplateSeoTags(template: string): string;
|
|
66
|
+
//# sourceMappingURL=seo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo.d.ts","sourceRoot":"","sources":["../../src/ssg/seo.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAMzD,4DAA4D;AAC5D,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,QAAQ,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAAA;CACzD;AAED,mEAAmE;AACnE,MAAM,WAAW,WAAW;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACtB;AAED,MAAM,WAAW,aAAa;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;CACnB;AAMD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE;IACtC,GAAG,EAAE,MAAM,CAAA;IACX,YAAY,EAAE,WAAW,GAAG,IAAI,CAAA;IAChC,OAAO,EAAE,WAAW,GAAG,IAAI,CAAA;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAA;CACpB,GAAG,MAAM,CAiFT;AAMD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,GAAG,MAAM,CA4CjE;AAMD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE;IAC3C,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,aAAa,EAAE,MAAM,CAAA;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAA;CACxB,GAAG,MAAM,CAmBT;AAMD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;IAC1C,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,OAAO,CAAC,EAAE,OAAO,CAAA;CACjB,GAAG,MAAM,CAmBT;AAMD,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,aAAa,EAAE,GAAG,MAAM,CAK3E;AAMD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAgB7D"}
|
package/dist/style.css
CHANGED
|
@@ -1,4 +1,23 @@
|
|
|
1
1
|
|
|
2
|
+
.blox-nav-progress {
|
|
3
|
+
position: fixed;
|
|
4
|
+
top: 0;
|
|
5
|
+
left: 0;
|
|
6
|
+
width: 100%;
|
|
7
|
+
height: 3px;
|
|
8
|
+
z-index: 9999;
|
|
9
|
+
background: linear-gradient(90deg, transparent, var(--blox-accent, #3b82f6), transparent);
|
|
10
|
+
animation: blox-nav-slide 1s ease-in-out infinite;
|
|
11
|
+
}
|
|
12
|
+
@keyframes blox-nav-slide {
|
|
13
|
+
0% {
|
|
14
|
+
transform: translateX(-100%);
|
|
15
|
+
}
|
|
16
|
+
100% {
|
|
17
|
+
transform: translateX(100%);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
2
21
|
* {
|
|
3
22
|
box-sizing: border-box;
|
|
4
23
|
}
|
|
@@ -8,6 +27,7 @@ body {
|
|
|
8
27
|
.blox-block-wrapper {
|
|
9
28
|
position: relative;
|
|
10
29
|
cursor: pointer;
|
|
30
|
+
display: contents;
|
|
11
31
|
}
|
|
12
32
|
.blox-block-overlay {
|
|
13
33
|
position: absolute;
|
package/dist/vite-plugin.cjs
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const node_module = require("node:module");
|
|
4
|
+
const path = require("node:path");
|
|
5
|
+
const process = require("node:process");
|
|
3
6
|
var comma = ",".charCodeAt(0);
|
|
4
7
|
var semicolon = ";".charCodeAt(0);
|
|
5
8
|
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
@@ -1069,8 +1072,143 @@ class MagicString {
|
|
|
1069
1072
|
return this._replaceRegexp(searchValue, replacement);
|
|
1070
1073
|
}
|
|
1071
1074
|
}
|
|
1072
|
-
function bloxPlugin() {
|
|
1073
|
-
|
|
1075
|
+
function bloxPlugin(options = {}) {
|
|
1076
|
+
const enableSSR = options.ssr ?? false;
|
|
1077
|
+
const plugins = [];
|
|
1078
|
+
if (enableSSR) {
|
|
1079
|
+
plugins.push({
|
|
1080
|
+
name: "vite-plugin-blox-ssr",
|
|
1081
|
+
enforce: "pre",
|
|
1082
|
+
config(_config, { command }) {
|
|
1083
|
+
const cwd = process.cwd();
|
|
1084
|
+
function resolveVuePaths() {
|
|
1085
|
+
const bases = [path.join(cwd, "..", "package.json"), path.join(cwd, "package.json")];
|
|
1086
|
+
for (const base of bases) {
|
|
1087
|
+
try {
|
|
1088
|
+
const req = node_module.createRequire(base);
|
|
1089
|
+
const vueEntry = req.resolve("vue");
|
|
1090
|
+
const vueDir = path.dirname(path.dirname(vueEntry));
|
|
1091
|
+
return {
|
|
1092
|
+
"vue": vueEntry,
|
|
1093
|
+
"vue/server-renderer": path.join(vueDir, "server-renderer", "index.mjs"),
|
|
1094
|
+
"@vue/server-renderer": req.resolve("@vue/server-renderer")
|
|
1095
|
+
};
|
|
1096
|
+
} catch {
|
|
1097
|
+
continue;
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
return {};
|
|
1101
|
+
}
|
|
1102
|
+
const dedupe = [
|
|
1103
|
+
"vue",
|
|
1104
|
+
"vue-router",
|
|
1105
|
+
"@vue/runtime-core",
|
|
1106
|
+
"@vue/runtime-dom",
|
|
1107
|
+
"@vue/reactivity",
|
|
1108
|
+
"pinia"
|
|
1109
|
+
];
|
|
1110
|
+
const alias = resolveVuePaths();
|
|
1111
|
+
const ssrConfig = {
|
|
1112
|
+
resolve: {
|
|
1113
|
+
dedupe,
|
|
1114
|
+
alias
|
|
1115
|
+
}
|
|
1116
|
+
};
|
|
1117
|
+
return ssrConfig;
|
|
1118
|
+
}
|
|
1119
|
+
});
|
|
1120
|
+
plugins.push({
|
|
1121
|
+
name: "vite-plugin-blox-ssr-build",
|
|
1122
|
+
enforce: "pre",
|
|
1123
|
+
config(config) {
|
|
1124
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
1125
|
+
if ((_a = config.build) == null ? void 0 : _a.ssr) {
|
|
1126
|
+
return {
|
|
1127
|
+
build: {
|
|
1128
|
+
rollupOptions: {
|
|
1129
|
+
input: ((_c = (_b = config.build) == null ? void 0 : _b.rollupOptions) == null ? void 0 : _c.input) ?? "src/main.server.ts",
|
|
1130
|
+
output: ((_e = (_d = config.build) == null ? void 0 : _d.rollupOptions) == null ? void 0 : _e.output) ?? {
|
|
1131
|
+
dir: "dist/server",
|
|
1132
|
+
format: "esm"
|
|
1133
|
+
},
|
|
1134
|
+
external: [
|
|
1135
|
+
"vue",
|
|
1136
|
+
"vue-router",
|
|
1137
|
+
"vue/server-renderer",
|
|
1138
|
+
"@vue/server-renderer",
|
|
1139
|
+
...Array.isArray((_g = (_f = config.build) == null ? void 0 : _f.rollupOptions) == null ? void 0 : _g.external) ? config.build.rollupOptions.external : []
|
|
1140
|
+
]
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
};
|
|
1144
|
+
}
|
|
1145
|
+
return {};
|
|
1146
|
+
}
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1149
|
+
if (options.autoCollections ?? false) {
|
|
1150
|
+
const discoveredCollections = /* @__PURE__ */ new Map();
|
|
1151
|
+
const VIRTUAL_ID = "virtual:blox-collections";
|
|
1152
|
+
const RESOLVED_VIRTUAL_ID = `\0${VIRTUAL_ID}`;
|
|
1153
|
+
plugins.push({
|
|
1154
|
+
name: "vite-plugin-blox-collections",
|
|
1155
|
+
enforce: "pre",
|
|
1156
|
+
resolveId(id) {
|
|
1157
|
+
if (id === VIRTUAL_ID) return RESOLVED_VIRTUAL_ID;
|
|
1158
|
+
},
|
|
1159
|
+
load(id) {
|
|
1160
|
+
if (id === RESOLVED_VIRTUAL_ID) {
|
|
1161
|
+
const entries = [...discoveredCollections.values()];
|
|
1162
|
+
return `export default ${JSON.stringify(entries)}`;
|
|
1163
|
+
}
|
|
1164
|
+
},
|
|
1165
|
+
transform(code, id) {
|
|
1166
|
+
if (!id.endsWith(".vue")) return;
|
|
1167
|
+
const namePatterns = [
|
|
1168
|
+
/collectionName\s*:\s*['"]([^'"]+)['"]/g,
|
|
1169
|
+
/collection_name\s*:\s*['"]([^'"]+)['"]/g,
|
|
1170
|
+
/collection\s*:\s*['"]([^'"]+)['"]/g
|
|
1171
|
+
];
|
|
1172
|
+
const storeRe = /store\s*:\s*['"]([^'"]+)['"]/g;
|
|
1173
|
+
const stores = [];
|
|
1174
|
+
let storeMatch;
|
|
1175
|
+
while ((storeMatch = storeRe.exec(code)) !== null) {
|
|
1176
|
+
stores.push(storeMatch[1]);
|
|
1177
|
+
}
|
|
1178
|
+
const listItemsRe = /listItems\s*\(\s*['"]([^'"]+)['"]/g;
|
|
1179
|
+
let listMatch;
|
|
1180
|
+
while ((listMatch = listItemsRe.exec(code)) !== null) {
|
|
1181
|
+
const collectionName = listMatch[1];
|
|
1182
|
+
const key = `*/${collectionName}`;
|
|
1183
|
+
if (!discoveredCollections.has(key)) {
|
|
1184
|
+
discoveredCollections.set(key, { store: "*", collection: collectionName });
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
for (const pattern of namePatterns) {
|
|
1188
|
+
let match;
|
|
1189
|
+
while ((match = pattern.exec(code)) !== null) {
|
|
1190
|
+
const collection = match[1];
|
|
1191
|
+
if (["name", "label", "icon", "description", "type"].includes(collection)) continue;
|
|
1192
|
+
const store = stores[0] ?? "*";
|
|
1193
|
+
const key = `${store}/${collection}`;
|
|
1194
|
+
if (!discoveredCollections.has(key)) {
|
|
1195
|
+
discoveredCollections.set(key, { store, collection });
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
},
|
|
1200
|
+
generateBundle() {
|
|
1201
|
+
if (discoveredCollections.size === 0) return;
|
|
1202
|
+
const entries = [...discoveredCollections.values()];
|
|
1203
|
+
this.emitFile({
|
|
1204
|
+
type: "asset",
|
|
1205
|
+
fileName: ".blox-collections.json",
|
|
1206
|
+
source: JSON.stringify(entries, null, 2)
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
});
|
|
1210
|
+
}
|
|
1211
|
+
plugins.push({
|
|
1074
1212
|
name: "vite-plugin-blox",
|
|
1075
1213
|
enforce: "pre",
|
|
1076
1214
|
transform(code, id) {
|
|
@@ -1163,6 +1301,7 @@ ${openTag}${remaining}${closeTag}`;
|
|
|
1163
1301
|
map: s.generateMap({ hires: true })
|
|
1164
1302
|
};
|
|
1165
1303
|
}
|
|
1166
|
-
};
|
|
1304
|
+
});
|
|
1305
|
+
return plugins;
|
|
1167
1306
|
}
|
|
1168
1307
|
exports.bloxPlugin = bloxPlugin;
|
package/dist/vite-plugin.d.ts
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
import { Plugin } from 'vite';
|
|
2
|
+
export interface BloxPluginOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Enable SSR-aware config injection.
|
|
5
|
+
* When true, adds `resolve.dedupe`, `resolve.alias` for Vue,
|
|
6
|
+
* and SSR build rollup options automatically.
|
|
7
|
+
* @default false
|
|
8
|
+
*/
|
|
9
|
+
ssr?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Enable collection auto-discovery from block source files.
|
|
12
|
+
* When true, scans `.vue` files for datastore collection references
|
|
13
|
+
* and emits a `virtual:blox-collections` module and a
|
|
14
|
+
* `.blox-collections.json` manifest in the output directory.
|
|
15
|
+
* @default false
|
|
16
|
+
*/
|
|
17
|
+
autoCollections?: boolean;
|
|
18
|
+
}
|
|
2
19
|
/**
|
|
3
|
-
* Vite plugin that
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```vue
|
|
9
|
-
* <script setup lang="ts">
|
|
10
|
-
* import { defineBlock } from '@bagelink/blox'
|
|
11
|
-
* import { defineSchema, $ } from '@bagelink/vue'
|
|
12
|
-
*
|
|
13
|
-
* // Either inline:
|
|
14
|
-
* defineBlock({ name: 'hero', label: 'Hero', schema: defineSchema({ ... }) })
|
|
15
|
-
*
|
|
16
|
-
* // Or via variable (also hoisted automatically):
|
|
17
|
-
* const schema = defineSchema({ ... })
|
|
18
|
-
* defineBlock({ name: 'hero', label: 'Hero', schema })
|
|
19
|
-
*
|
|
20
|
-
* defineProps<HeroProps>()
|
|
21
|
-
* </script>
|
|
22
|
-
* ```
|
|
20
|
+
* Vite plugin that:
|
|
21
|
+
* 1. Hoists `defineBlock(...)` out of `<script setup>` into a plain `<script>` block.
|
|
22
|
+
* 2. (When `ssr: true`) Injects Vue dedupe, alias, and SSR rollup config
|
|
23
|
+
* so consumer `vite.config.ts` doesn't need any of that boilerplate.
|
|
23
24
|
*/
|
|
24
|
-
export declare function bloxPlugin(): Plugin;
|
|
25
|
+
export declare function bloxPlugin(options?: BloxPluginOptions): Plugin[];
|
|
25
26
|
//# sourceMappingURL=vite-plugin.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vite-plugin.d.ts","sourceRoot":"","sources":["../src/vite-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"vite-plugin.d.ts","sourceRoot":"","sources":["../src/vite-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAc,MAAM,MAAM,CAAA;AAM9C,MAAM,WAAW,iBAAiB;IACjC;;;;;OAKG;IACH,GAAG,CAAC,EAAE,OAAO,CAAA;IACb;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;CACzB;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,MAAM,EAAE,CA4SpE"}
|