@constela/start 1.2.18 → 1.2.20
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.
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
generateHydrationScript,
|
|
3
3
|
renderPage,
|
|
4
4
|
wrapHtml
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-LIHJUGSX.js";
|
|
6
6
|
|
|
7
7
|
// src/router/file-router.ts
|
|
8
8
|
import fg from "fast-glob";
|
|
@@ -2782,7 +2782,7 @@ async function processLayouts(pageInfo, layoutsDir, routeParams = {}) {
|
|
|
2782
2782
|
};
|
|
2783
2783
|
return updatedPageInfo;
|
|
2784
2784
|
}
|
|
2785
|
-
async function renderPageToHtml(program, params, runtimePath, cssPath) {
|
|
2785
|
+
async function renderPageToHtml(program, params, runtimePath, cssPath, externalImports) {
|
|
2786
2786
|
const normalizedProgram = {
|
|
2787
2787
|
...program,
|
|
2788
2788
|
view: normalizeViewNode(structuredClone(program.view))
|
|
@@ -2800,7 +2800,24 @@ async function renderPageToHtml(program, params, runtimePath, cssPath) {
|
|
|
2800
2800
|
};
|
|
2801
2801
|
const cssLinkTag = cssPath ? `<link rel="stylesheet" href="${cssPath}">` : void 0;
|
|
2802
2802
|
const hydrationScript = generateHydrationScript(normalizedProgram, void 0, routeContext);
|
|
2803
|
-
|
|
2803
|
+
const wrapOptions = {};
|
|
2804
|
+
if (runtimePath) {
|
|
2805
|
+
wrapOptions.runtimePath = runtimePath;
|
|
2806
|
+
}
|
|
2807
|
+
if (externalImports && Object.keys(externalImports).length > 0) {
|
|
2808
|
+
wrapOptions.importMap = externalImports;
|
|
2809
|
+
}
|
|
2810
|
+
const themeState = program.state?.["theme"];
|
|
2811
|
+
if (themeState?.initial) {
|
|
2812
|
+
wrapOptions.defaultTheme = themeState.initial;
|
|
2813
|
+
wrapOptions.themeStorageKey = "theme";
|
|
2814
|
+
}
|
|
2815
|
+
return wrapHtml(
|
|
2816
|
+
content,
|
|
2817
|
+
hydrationScript,
|
|
2818
|
+
cssLinkTag,
|
|
2819
|
+
Object.keys(wrapOptions).length > 0 ? wrapOptions : void 0
|
|
2820
|
+
);
|
|
2804
2821
|
}
|
|
2805
2822
|
async function copyPublicDir(publicDir, outDir, generatedFiles) {
|
|
2806
2823
|
if (!existsSync8(publicDir)) {
|
|
@@ -2911,13 +2928,12 @@ async function build2(options) {
|
|
|
2911
2928
|
let boundPageInfo = pageInfo;
|
|
2912
2929
|
if (pathEntry.data && pageInfo.page.getStaticPaths?.source) {
|
|
2913
2930
|
const source = pageInfo.page.getStaticPaths.source;
|
|
2914
|
-
|
|
2915
|
-
if (sourceName) {
|
|
2931
|
+
if (typeof source === "string") {
|
|
2916
2932
|
boundPageInfo = {
|
|
2917
2933
|
...pageInfo,
|
|
2918
2934
|
loadedData: {
|
|
2919
2935
|
...pageInfo.loadedData,
|
|
2920
|
-
[
|
|
2936
|
+
[source]: pathEntry.data
|
|
2921
2937
|
// Replace array with current item
|
|
2922
2938
|
}
|
|
2923
2939
|
};
|
|
@@ -2928,10 +2944,19 @@ async function build2(options) {
|
|
|
2928
2944
|
processedPageInfo = await processLayouts(boundPageInfo, layoutsDir, params);
|
|
2929
2945
|
}
|
|
2930
2946
|
const program = await convertToCompiledProgram(processedPageInfo);
|
|
2931
|
-
const html = await renderPageToHtml(program, params, runtimePath, cssPath);
|
|
2947
|
+
const html = await renderPageToHtml(program, params, runtimePath, cssPath, processedPageInfo.page.externalImports);
|
|
2932
2948
|
await mkdir2(dirname5(outputPath), { recursive: true });
|
|
2933
2949
|
await writeFile(outputPath, html, "utf-8");
|
|
2934
2950
|
generatedFiles.push(outputPath);
|
|
2951
|
+
const slugValue = params["slug"];
|
|
2952
|
+
if (slugValue && (slugValue === "index" || slugValue.endsWith("/index"))) {
|
|
2953
|
+
const parentOutputPath = join9(dirname5(dirname5(outputPath)), "index.html");
|
|
2954
|
+
if (!generatedFiles.includes(parentOutputPath)) {
|
|
2955
|
+
await mkdir2(dirname5(parentOutputPath), { recursive: true });
|
|
2956
|
+
await writeFile(parentOutputPath, html, "utf-8");
|
|
2957
|
+
generatedFiles.push(parentOutputPath);
|
|
2958
|
+
}
|
|
2959
|
+
}
|
|
2935
2960
|
let routePath = route.pattern;
|
|
2936
2961
|
for (const [key, value] of Object.entries(params)) {
|
|
2937
2962
|
routePath = routePath.replace(`:${key}`, value);
|
|
@@ -2958,7 +2983,7 @@ async function build2(options) {
|
|
|
2958
2983
|
pageInfo = await processLayouts(pageInfo, layoutsDir, {});
|
|
2959
2984
|
}
|
|
2960
2985
|
const program = await convertToCompiledProgram(pageInfo);
|
|
2961
|
-
const html = await renderPageToHtml(program, {}, runtimePath, cssPath);
|
|
2986
|
+
const html = await renderPageToHtml(program, {}, runtimePath, cssPath, pageInfo.page.externalImports);
|
|
2962
2987
|
await mkdir2(dirname5(outputPath), { recursive: true });
|
|
2963
2988
|
await writeFile(outputPath, html, "utf-8");
|
|
2964
2989
|
generatedFiles.push(outputPath);
|
|
@@ -71,7 +71,7 @@ ${routeDeclaration ? "\n" + routeDeclaration : ""}${widgetDeclarations ? "\n" +
|
|
|
71
71
|
hydrateApp(${hydrateOptions});${widgetMounting}`;
|
|
72
72
|
}
|
|
73
73
|
function wrapHtml(content, hydrationScript, head, options) {
|
|
74
|
-
const htmlClass = options?.theme === "dark" ? ' class="dark"' : "";
|
|
74
|
+
const htmlClass = options?.defaultTheme === "dark" || options?.theme === "dark" ? ' class="dark"' : "";
|
|
75
75
|
let processedScript = hydrationScript;
|
|
76
76
|
let importMapScript = "";
|
|
77
77
|
if (options?.runtimePath) {
|
|
@@ -82,11 +82,37 @@ function wrapHtml(content, hydrationScript, head, options) {
|
|
|
82
82
|
/from\s+['"]@constela\/runtime['"]/g,
|
|
83
83
|
`from '${options.runtimePath}'`
|
|
84
84
|
);
|
|
85
|
+
if (options?.importMap && Object.keys(options.importMap).length > 0) {
|
|
86
|
+
const importMapJson = JSON.stringify({ imports: options.importMap }, null, 2);
|
|
87
|
+
importMapScript = `<script type="importmap">
|
|
88
|
+
${importMapJson}
|
|
89
|
+
</script>
|
|
90
|
+
`;
|
|
91
|
+
}
|
|
85
92
|
} else if (options?.importMap && Object.keys(options.importMap).length > 0) {
|
|
86
93
|
const importMapJson = JSON.stringify({ imports: options.importMap }, null, 2);
|
|
87
94
|
importMapScript = `<script type="importmap">
|
|
88
95
|
${importMapJson}
|
|
89
96
|
</script>
|
|
97
|
+
`;
|
|
98
|
+
}
|
|
99
|
+
let themeScript = "";
|
|
100
|
+
if (options?.themeStorageKey) {
|
|
101
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(options.themeStorageKey)) {
|
|
102
|
+
throw new Error(`Invalid themeStorageKey: ${options.themeStorageKey}. Only alphanumeric characters, underscores, and hyphens are allowed.`);
|
|
103
|
+
}
|
|
104
|
+
themeScript = `<script>
|
|
105
|
+
(function() {
|
|
106
|
+
try {
|
|
107
|
+
var theme = localStorage.getItem('${options.themeStorageKey}');
|
|
108
|
+
if (theme === 'dark') {
|
|
109
|
+
document.documentElement.classList.add('dark');
|
|
110
|
+
} else if (theme === 'light') {
|
|
111
|
+
document.documentElement.classList.remove('dark');
|
|
112
|
+
}
|
|
113
|
+
} catch (e) {}
|
|
114
|
+
})();
|
|
115
|
+
</script>
|
|
90
116
|
`;
|
|
91
117
|
}
|
|
92
118
|
return `<!DOCTYPE html>
|
|
@@ -94,7 +120,7 @@ ${importMapJson}
|
|
|
94
120
|
<head>
|
|
95
121
|
<meta charset="utf-8">
|
|
96
122
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
97
|
-
${importMapScript}${head ?? ""}
|
|
123
|
+
${themeScript}${importMapScript}${head ?? ""}
|
|
98
124
|
</head>
|
|
99
125
|
<body>
|
|
100
126
|
<div id="app">${content}</div>
|
package/dist/cli/index.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -23,12 +23,12 @@ import {
|
|
|
23
23
|
transformCsv,
|
|
24
24
|
transformMdx,
|
|
25
25
|
transformYaml
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-AXCIL6BP.js";
|
|
27
27
|
import {
|
|
28
28
|
generateHydrationScript,
|
|
29
29
|
renderPage,
|
|
30
30
|
wrapHtml
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-LIHJUGSX.js";
|
|
32
32
|
|
|
33
33
|
// src/build/ssg.ts
|
|
34
34
|
import { mkdir, writeFile } from "fs/promises";
|
|
@@ -112,7 +112,18 @@ async function generateSinglePage(pattern, outDir, program, params = {}) {
|
|
|
112
112
|
path: pattern
|
|
113
113
|
};
|
|
114
114
|
const hydrationScript = generateHydrationScript(program, void 0, routeContext);
|
|
115
|
-
const
|
|
115
|
+
const wrapOptions = {};
|
|
116
|
+
const themeState = program.state?.["theme"];
|
|
117
|
+
if (themeState?.initial) {
|
|
118
|
+
wrapOptions.defaultTheme = themeState.initial;
|
|
119
|
+
wrapOptions.themeStorageKey = "theme";
|
|
120
|
+
}
|
|
121
|
+
const html = wrapHtml(
|
|
122
|
+
content,
|
|
123
|
+
hydrationScript,
|
|
124
|
+
void 0,
|
|
125
|
+
Object.keys(wrapOptions).length > 0 ? wrapOptions : void 0
|
|
126
|
+
);
|
|
116
127
|
await writeFile(outputPath, html, "utf-8");
|
|
117
128
|
return outputPath;
|
|
118
129
|
}
|
|
@@ -16,6 +16,10 @@ interface WrapHtmlOptions {
|
|
|
16
16
|
importMap?: Record<string, string>;
|
|
17
17
|
/** Path to bundled runtime for production builds. When provided, replaces @constela/runtime imports and excludes importmap. */
|
|
18
18
|
runtimePath?: string;
|
|
19
|
+
/** localStorage key for theme persistence. When provided, generates anti-flash script. */
|
|
20
|
+
themeStorageKey?: string;
|
|
21
|
+
/** Default theme to use when no stored preference exists */
|
|
22
|
+
defaultTheme?: 'dark' | 'light';
|
|
19
23
|
}
|
|
20
24
|
interface WidgetConfig {
|
|
21
25
|
/** The DOM element ID where the widget should be mounted */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@constela/start",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.20",
|
|
4
4
|
"description": "Meta-framework for Constela applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -43,11 +43,11 @@
|
|
|
43
43
|
"postcss": "^8.5.0",
|
|
44
44
|
"@tailwindcss/postcss": "^4.0.0",
|
|
45
45
|
"tailwindcss": "^4.0.0",
|
|
46
|
-
"@constela/
|
|
46
|
+
"@constela/compiler": "0.7.1",
|
|
47
47
|
"@constela/core": "0.7.0",
|
|
48
48
|
"@constela/runtime": "0.10.2",
|
|
49
|
-
"@constela/
|
|
50
|
-
"@constela/
|
|
49
|
+
"@constela/server": "3.0.1",
|
|
50
|
+
"@constela/router": "8.0.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@types/mdast": "^4.0.4",
|