@constela/start 1.3.5 → 1.4.0
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.
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
generateHydrationScript,
|
|
3
|
+
generateMetaTags,
|
|
3
4
|
renderPage,
|
|
4
5
|
wrapHtml
|
|
5
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-XAC4ETQU.js";
|
|
6
7
|
|
|
7
8
|
// src/router/file-router.ts
|
|
8
9
|
import fg from "fast-glob";
|
|
@@ -2172,7 +2173,13 @@ async function createDevServer(options = {}) {
|
|
|
2172
2173
|
path: pathname
|
|
2173
2174
|
};
|
|
2174
2175
|
const hydrationScript = generateHydrationScript(composedProgram, widgets, routeContext);
|
|
2176
|
+
const metaTags = generateMetaTags(composedProgram.route, {
|
|
2177
|
+
params: match.params,
|
|
2178
|
+
query: Object.fromEntries(url.searchParams.entries()),
|
|
2179
|
+
path: pathname
|
|
2180
|
+
});
|
|
2175
2181
|
const cssHead = css ? (Array.isArray(css) ? css : [css]).map((p) => `<link rel="stylesheet" href="/${p}">`).join("\n") : "";
|
|
2182
|
+
const head = [metaTags, cssHead].filter(Boolean).join("\n");
|
|
2176
2183
|
const themeState = composedProgram.state?.["theme"];
|
|
2177
2184
|
const initialTheme = themeState?.initial;
|
|
2178
2185
|
const importMap = {
|
|
@@ -2182,7 +2189,7 @@ async function createDevServer(options = {}) {
|
|
|
2182
2189
|
"marked": "/node_modules/marked/lib/marked.esm.js",
|
|
2183
2190
|
"monaco-editor": "/node_modules/monaco-editor/esm/vs/editor/editor.api.js"
|
|
2184
2191
|
};
|
|
2185
|
-
const html = wrapHtml(content, hydrationScript,
|
|
2192
|
+
const html = wrapHtml(content, hydrationScript, head || void 0, {
|
|
2186
2193
|
...initialTheme ? {
|
|
2187
2194
|
theme: initialTheme,
|
|
2188
2195
|
defaultTheme: initialTheme,
|
|
@@ -136,9 +136,65 @@ ${processedScript}
|
|
|
136
136
|
</body>
|
|
137
137
|
</html>`;
|
|
138
138
|
}
|
|
139
|
+
function escapeHtmlForMeta(str) {
|
|
140
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
141
|
+
}
|
|
142
|
+
function evaluateMetaExpression(expr, ctx) {
|
|
143
|
+
switch (expr.expr) {
|
|
144
|
+
case "lit":
|
|
145
|
+
return String(expr.value);
|
|
146
|
+
case "route":
|
|
147
|
+
if (expr.source === "param") {
|
|
148
|
+
return ctx.params[expr.name] || "";
|
|
149
|
+
} else if (expr.source === "query") {
|
|
150
|
+
return ctx.query[expr.name] || "";
|
|
151
|
+
} else if (expr.source === "path") {
|
|
152
|
+
return ctx.path;
|
|
153
|
+
}
|
|
154
|
+
return "";
|
|
155
|
+
case "bin":
|
|
156
|
+
if (expr.op === "+") {
|
|
157
|
+
return evaluateMetaExpression(expr.left, ctx) + evaluateMetaExpression(expr.right, ctx);
|
|
158
|
+
}
|
|
159
|
+
return "";
|
|
160
|
+
case "concat":
|
|
161
|
+
return expr.items.map((item) => evaluateMetaExpression(item, ctx)).join("");
|
|
162
|
+
default:
|
|
163
|
+
return "";
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function generateMetaTags(route, ctx) {
|
|
167
|
+
if (!route) {
|
|
168
|
+
return "";
|
|
169
|
+
}
|
|
170
|
+
const tags = [];
|
|
171
|
+
if (route.title) {
|
|
172
|
+
const titleValue = evaluateMetaExpression(route.title, ctx);
|
|
173
|
+
if (titleValue) {
|
|
174
|
+
tags.push(`<title>${escapeHtmlForMeta(titleValue)}</title>`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (route.meta) {
|
|
178
|
+
for (const [key, expr] of Object.entries(route.meta)) {
|
|
179
|
+
const value = evaluateMetaExpression(expr, ctx);
|
|
180
|
+
if (!value) {
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
const escapedValue = escapeHtmlForMeta(value);
|
|
184
|
+
if (key.startsWith("og:") || key.startsWith("twitter:")) {
|
|
185
|
+
tags.push(`<meta property="${key}" content="${escapedValue}">`);
|
|
186
|
+
} else {
|
|
187
|
+
tags.push(`<meta name="${key}" content="${escapedValue}">`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return tags.join("\n");
|
|
192
|
+
}
|
|
139
193
|
|
|
140
194
|
export {
|
|
141
195
|
renderPage,
|
|
142
196
|
generateHydrationScript,
|
|
143
|
-
wrapHtml
|
|
197
|
+
wrapHtml,
|
|
198
|
+
evaluateMetaExpression,
|
|
199
|
+
generateMetaTags
|
|
144
200
|
};
|
package/dist/cli/index.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -24,12 +24,13 @@ import {
|
|
|
24
24
|
transformCsv,
|
|
25
25
|
transformMdx,
|
|
26
26
|
transformYaml
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-6FV75N45.js";
|
|
28
28
|
import {
|
|
29
29
|
generateHydrationScript,
|
|
30
|
+
generateMetaTags,
|
|
30
31
|
renderPage,
|
|
31
32
|
wrapHtml
|
|
32
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-XAC4ETQU.js";
|
|
33
34
|
|
|
34
35
|
// src/build/ssg.ts
|
|
35
36
|
import { mkdir, writeFile } from "fs/promises";
|
|
@@ -113,6 +114,11 @@ async function generateSinglePage(pattern, outDir, program, params = {}) {
|
|
|
113
114
|
path: pattern
|
|
114
115
|
};
|
|
115
116
|
const hydrationScript = generateHydrationScript(program, void 0, routeContext);
|
|
117
|
+
const metaTags = generateMetaTags(program.route, {
|
|
118
|
+
params,
|
|
119
|
+
query: {},
|
|
120
|
+
path: pattern
|
|
121
|
+
});
|
|
116
122
|
const wrapOptions = {};
|
|
117
123
|
const themeState = program.state?.["theme"];
|
|
118
124
|
if (themeState?.initial) {
|
|
@@ -122,7 +128,7 @@ async function generateSinglePage(pattern, outDir, program, params = {}) {
|
|
|
122
128
|
const html = wrapHtml(
|
|
123
129
|
content,
|
|
124
130
|
hydrationScript,
|
|
125
|
-
void 0,
|
|
131
|
+
metaTags || void 0,
|
|
126
132
|
Object.keys(wrapOptions).length > 0 ? wrapOptions : void 0
|
|
127
133
|
);
|
|
128
134
|
await writeFile(outputPath, html, "utf-8");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CompiledProgram } from '@constela/compiler';
|
|
1
|
+
import { CompiledProgram, CompiledExpression, CompiledRouteDefinition } from '@constela/compiler';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Server-side entry point for Constela applications
|
|
@@ -76,5 +76,21 @@ declare function generateHydrationScript(program: CompiledProgram, widgets?: Wid
|
|
|
76
76
|
* @returns Complete HTML document string
|
|
77
77
|
*/
|
|
78
78
|
declare function wrapHtml(content: string, hydrationScript: string, head?: string, options?: WrapHtmlOptions): string;
|
|
79
|
+
/**
|
|
80
|
+
* Context for evaluating meta tag expressions
|
|
81
|
+
*/
|
|
82
|
+
interface MetaContext {
|
|
83
|
+
params: Record<string, string>;
|
|
84
|
+
query: Record<string, string>;
|
|
85
|
+
path: string;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Evaluates a compiled expression for meta tag values.
|
|
89
|
+
*/
|
|
90
|
+
declare function evaluateMetaExpression(expr: CompiledExpression, ctx: MetaContext): string;
|
|
91
|
+
/**
|
|
92
|
+
* Generates HTML meta tags from route definition.
|
|
93
|
+
*/
|
|
94
|
+
declare function generateMetaTags(route: CompiledRouteDefinition | undefined, ctx: MetaContext): string;
|
|
79
95
|
|
|
80
|
-
export { type HydrationRouteContext, type SSRContext, type WidgetConfig, type WrapHtmlOptions, generateHydrationScript, renderPage, wrapHtml };
|
|
96
|
+
export { type HydrationRouteContext, type MetaContext, type SSRContext, type WidgetConfig, type WrapHtmlOptions, evaluateMetaExpression, generateHydrationScript, generateMetaTags, renderPage, wrapHtml };
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
|
+
evaluateMetaExpression,
|
|
2
3
|
generateHydrationScript,
|
|
4
|
+
generateMetaTags,
|
|
3
5
|
renderPage,
|
|
4
6
|
wrapHtml
|
|
5
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-XAC4ETQU.js";
|
|
6
8
|
export {
|
|
9
|
+
evaluateMetaExpression,
|
|
7
10
|
generateHydrationScript,
|
|
11
|
+
generateMetaTags,
|
|
8
12
|
renderPage,
|
|
9
13
|
wrapHtml
|
|
10
14
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@constela/start",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Meta-framework for Constela applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -43,9 +43,9 @@
|
|
|
43
43
|
"postcss": "^8.5.0",
|
|
44
44
|
"@tailwindcss/postcss": "^4.0.0",
|
|
45
45
|
"tailwindcss": "^4.0.0",
|
|
46
|
-
"@constela/core": "0.10.0",
|
|
47
46
|
"@constela/compiler": "0.10.0",
|
|
48
47
|
"@constela/router": "11.0.0",
|
|
48
|
+
"@constela/core": "0.10.0",
|
|
49
49
|
"@constela/runtime": "0.13.0",
|
|
50
50
|
"@constela/server": "6.0.0"
|
|
51
51
|
},
|