@constela/start 1.1.0 → 1.2.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/chunk-6AN7W7KZ.js +2553 -0
- package/dist/chunk-PUTC5BCP.js +112 -0
- package/dist/cli/index.d.ts +9 -2
- package/dist/cli/index.js +98 -10
- package/dist/index.d.ts +24 -8
- package/dist/index.js +39 -915
- package/dist/runtime/entry-client.d.ts +10 -1
- package/dist/runtime/entry-client.js +21 -7
- package/dist/runtime/entry-server.d.ts +30 -5
- package/dist/runtime/entry-server.js +1 -1
- package/package.json +6 -5
- package/dist/chunk-JXIOHPG5.js +0 -399
- package/dist/chunk-QLDID7EZ.js +0 -49
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// src/runtime/entry-server.ts
|
|
2
|
+
import { renderToString } from "@constela/server";
|
|
3
|
+
async function renderPage(program, ctx) {
|
|
4
|
+
const options = {
|
|
5
|
+
route: {
|
|
6
|
+
params: ctx.params,
|
|
7
|
+
query: Object.fromEntries(ctx.query.entries()),
|
|
8
|
+
path: ctx.url
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
if (program.importData) {
|
|
12
|
+
options.imports = program.importData;
|
|
13
|
+
}
|
|
14
|
+
return await renderToString(program, options);
|
|
15
|
+
}
|
|
16
|
+
function escapeJsString(str) {
|
|
17
|
+
return str.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n").replace(/\r/g, "\\r");
|
|
18
|
+
}
|
|
19
|
+
function escapeJsonForScript(json) {
|
|
20
|
+
return json.replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
21
|
+
}
|
|
22
|
+
function serializeProgram(program) {
|
|
23
|
+
const serializable = {
|
|
24
|
+
...program,
|
|
25
|
+
// Convert Map to Object if actions is a Map
|
|
26
|
+
actions: program.actions instanceof Map ? Object.fromEntries(program.actions.entries()) : program.actions
|
|
27
|
+
};
|
|
28
|
+
return JSON.stringify(serializable);
|
|
29
|
+
}
|
|
30
|
+
function toJsIdentifier(id) {
|
|
31
|
+
let result = id.replace(/[^a-zA-Z0-9]/g, "_");
|
|
32
|
+
if (/^[0-9]/.test(result)) {
|
|
33
|
+
result = "_" + result;
|
|
34
|
+
}
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
function generateHydrationScript(program, widgets, route) {
|
|
38
|
+
const serializedProgram = escapeJsonForScript(serializeProgram(program));
|
|
39
|
+
const hasWidgets = widgets && widgets.length > 0;
|
|
40
|
+
const imports = hasWidgets ? `import { hydrateApp, createApp } from '@constela/runtime';` : `import { hydrateApp } from '@constela/runtime';`;
|
|
41
|
+
const widgetDeclarations = hasWidgets ? widgets.map((widget) => {
|
|
42
|
+
const jsId = toJsIdentifier(widget.id);
|
|
43
|
+
const serializedWidget = escapeJsonForScript(
|
|
44
|
+
serializeProgram(widget.program)
|
|
45
|
+
);
|
|
46
|
+
return `const widgetProgram_${jsId} = ${serializedWidget};`;
|
|
47
|
+
}).join("\n") : "";
|
|
48
|
+
const widgetMounting = hasWidgets ? widgets.map((widget) => {
|
|
49
|
+
const jsId = toJsIdentifier(widget.id);
|
|
50
|
+
const escapedId = escapeJsString(widget.id);
|
|
51
|
+
return `
|
|
52
|
+
const container_${jsId} = document.getElementById('${escapedId}');
|
|
53
|
+
if (container_${jsId}) {
|
|
54
|
+
container_${jsId}.innerHTML = '';
|
|
55
|
+
createApp(widgetProgram_${jsId}, container_${jsId});
|
|
56
|
+
}`;
|
|
57
|
+
}).join("\n") : "";
|
|
58
|
+
const routeDeclaration = route ? `const route = ${escapeJsonForScript(JSON.stringify(route))};` : "";
|
|
59
|
+
const hydrateOptions = route ? `{
|
|
60
|
+
program,
|
|
61
|
+
container: document.getElementById('app'),
|
|
62
|
+
route
|
|
63
|
+
}` : `{
|
|
64
|
+
program,
|
|
65
|
+
container: document.getElementById('app')
|
|
66
|
+
}`;
|
|
67
|
+
return `${imports}
|
|
68
|
+
|
|
69
|
+
const program = ${serializedProgram};
|
|
70
|
+
${routeDeclaration ? "\n" + routeDeclaration : ""}${widgetDeclarations ? "\n" + widgetDeclarations : ""}
|
|
71
|
+
hydrateApp(${hydrateOptions});${widgetMounting}`;
|
|
72
|
+
}
|
|
73
|
+
function wrapHtml(content, hydrationScript, head, options) {
|
|
74
|
+
const htmlClass = options?.theme === "dark" ? ' class="dark"' : "";
|
|
75
|
+
let processedScript = hydrationScript;
|
|
76
|
+
let importMapScript = "";
|
|
77
|
+
if (options?.runtimePath) {
|
|
78
|
+
if (!/^[a-zA-Z0-9/_.-]+$/.test(options.runtimePath)) {
|
|
79
|
+
throw new Error(`Invalid runtimePath: ${options.runtimePath}. Only alphanumeric characters, slashes, underscores, dots, and hyphens are allowed.`);
|
|
80
|
+
}
|
|
81
|
+
processedScript = hydrationScript.replace(
|
|
82
|
+
/from\s+['"]@constela\/runtime['"]/g,
|
|
83
|
+
`from '${options.runtimePath}'`
|
|
84
|
+
);
|
|
85
|
+
} else 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
|
+
}
|
|
92
|
+
return `<!DOCTYPE html>
|
|
93
|
+
<html${htmlClass}>
|
|
94
|
+
<head>
|
|
95
|
+
<meta charset="utf-8">
|
|
96
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
97
|
+
${importMapScript}${head ?? ""}
|
|
98
|
+
</head>
|
|
99
|
+
<body>
|
|
100
|
+
<div id="app">${content}</div>
|
|
101
|
+
<script type="module">
|
|
102
|
+
${processedScript}
|
|
103
|
+
</script>
|
|
104
|
+
</body>
|
|
105
|
+
</html>`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export {
|
|
109
|
+
renderPage,
|
|
110
|
+
generateHydrationScript,
|
|
111
|
+
wrapHtml
|
|
112
|
+
};
|
package/dist/cli/index.d.ts
CHANGED
|
@@ -2,15 +2,22 @@ import { Command } from 'commander';
|
|
|
2
2
|
|
|
3
3
|
type DevHandler = (options: {
|
|
4
4
|
port: string;
|
|
5
|
-
host?: string;
|
|
5
|
+
host?: string | undefined;
|
|
6
|
+
css?: string | undefined;
|
|
7
|
+
layoutsDir?: string | undefined;
|
|
6
8
|
}) => Promise<{
|
|
7
9
|
port: number;
|
|
8
10
|
}>;
|
|
9
11
|
type BuildHandler = (options: {
|
|
10
|
-
outDir?: string;
|
|
12
|
+
outDir?: string | undefined;
|
|
13
|
+
css?: string | undefined;
|
|
14
|
+
layoutsDir?: string | undefined;
|
|
11
15
|
}) => Promise<void>;
|
|
12
16
|
type StartHandler = (options: {
|
|
13
17
|
port: string;
|
|
18
|
+
host?: string | undefined;
|
|
19
|
+
css?: string | undefined;
|
|
20
|
+
layoutsDir?: string | undefined;
|
|
14
21
|
}) => Promise<{
|
|
15
22
|
port: number;
|
|
16
23
|
}>;
|
package/dist/cli/index.js
CHANGED
|
@@ -1,14 +1,63 @@
|
|
|
1
1
|
import {
|
|
2
2
|
build,
|
|
3
3
|
createDevServer
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-6AN7W7KZ.js";
|
|
5
|
+
import "../chunk-PUTC5BCP.js";
|
|
5
6
|
|
|
6
7
|
// src/cli/index.ts
|
|
7
8
|
import { Command } from "commander";
|
|
9
|
+
|
|
10
|
+
// src/config/config-loader.ts
|
|
11
|
+
import { existsSync, readFileSync } from "fs";
|
|
12
|
+
import { join } from "path";
|
|
13
|
+
var CONFIG_FILENAME = "constela.config.json";
|
|
14
|
+
async function loadConfig(projectRoot) {
|
|
15
|
+
const configPath = join(projectRoot, CONFIG_FILENAME);
|
|
16
|
+
if (!existsSync(configPath)) {
|
|
17
|
+
return {};
|
|
18
|
+
}
|
|
19
|
+
let content;
|
|
20
|
+
try {
|
|
21
|
+
content = readFileSync(configPath, "utf-8");
|
|
22
|
+
} catch (error) {
|
|
23
|
+
throw new Error(`Failed to read config file: ${configPath}`);
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
return JSON.parse(content);
|
|
27
|
+
} catch {
|
|
28
|
+
throw new Error(`Invalid JSON in config file: ${configPath}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
async function resolveConfig(fileConfig, cliOptions) {
|
|
32
|
+
if (!cliOptions) {
|
|
33
|
+
return { ...fileConfig };
|
|
34
|
+
}
|
|
35
|
+
const result = { ...fileConfig };
|
|
36
|
+
if (cliOptions.css !== void 0) result.css = cliOptions.css;
|
|
37
|
+
if (cliOptions.layoutsDir !== void 0) result.layoutsDir = cliOptions.layoutsDir;
|
|
38
|
+
if (cliOptions.routesDir !== void 0) result.routesDir = cliOptions.routesDir;
|
|
39
|
+
if (cliOptions.publicDir !== void 0) result.publicDir = cliOptions.publicDir;
|
|
40
|
+
if (cliOptions.outDir !== void 0) {
|
|
41
|
+
result.build = { ...result.build, outDir: cliOptions.outDir };
|
|
42
|
+
}
|
|
43
|
+
if (cliOptions.port !== void 0 || cliOptions.host !== void 0) {
|
|
44
|
+
result.dev = { ...result.dev };
|
|
45
|
+
if (cliOptions.port !== void 0) result.dev.port = cliOptions.port;
|
|
46
|
+
if (cliOptions.host !== void 0) result.dev.host = cliOptions.host;
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// src/cli/index.ts
|
|
8
52
|
var devHandler = async (options) => {
|
|
9
53
|
const port = parseInt(options.port, 10);
|
|
10
54
|
const host = options.host ?? "localhost";
|
|
11
|
-
const server = await createDevServer({
|
|
55
|
+
const server = await createDevServer({
|
|
56
|
+
port,
|
|
57
|
+
host,
|
|
58
|
+
...options.css ? { css: options.css } : {},
|
|
59
|
+
...options.layoutsDir ? { layoutsDir: options.layoutsDir } : {}
|
|
60
|
+
});
|
|
12
61
|
await server.listen();
|
|
13
62
|
console.log(`Development server running at http://${host}:${server.port}`);
|
|
14
63
|
process.on("SIGINT", async () => {
|
|
@@ -20,14 +69,24 @@ var devHandler = async (options) => {
|
|
|
20
69
|
};
|
|
21
70
|
var buildHandler = async (options) => {
|
|
22
71
|
console.log("Building for production...");
|
|
23
|
-
await build(
|
|
72
|
+
await build({
|
|
73
|
+
outDir: options.outDir,
|
|
74
|
+
layoutsDir: options.layoutsDir,
|
|
75
|
+
css: options.css
|
|
76
|
+
});
|
|
24
77
|
console.log("Build complete");
|
|
25
78
|
};
|
|
26
79
|
var startHandler = async (options) => {
|
|
27
80
|
const port = parseInt(options.port, 10);
|
|
28
|
-
const
|
|
81
|
+
const host = options.host ?? "0.0.0.0";
|
|
82
|
+
const server = await createDevServer({
|
|
83
|
+
port,
|
|
84
|
+
host,
|
|
85
|
+
...options.css ? { css: options.css } : {},
|
|
86
|
+
...options.layoutsDir ? { layoutsDir: options.layoutsDir } : {}
|
|
87
|
+
});
|
|
29
88
|
await server.listen();
|
|
30
|
-
console.log(`Production server running at http
|
|
89
|
+
console.log(`Production server running at http://${host}:${server.port}`);
|
|
31
90
|
process.on("SIGINT", async () => {
|
|
32
91
|
console.log("\nShutting down server...");
|
|
33
92
|
await server.close();
|
|
@@ -47,14 +106,43 @@ function setStartHandler(handler) {
|
|
|
47
106
|
function createCLI() {
|
|
48
107
|
const program = new Command();
|
|
49
108
|
program.name("constela-start").version("0.1.0").description("Meta-framework for Constela applications");
|
|
50
|
-
program.command("dev").description("Start development server").option("-p, --port <port>", "Port number", "3000").option("-h, --host <host>", "Host address").action(async (options) => {
|
|
109
|
+
program.command("dev").description("Start development server").option("-p, --port <port>", "Port number", "3000").option("-h, --host <host>", "Host address").option("-c, --css <path>", "CSS entry point for Vite processing").option("-l, --layoutsDir <path>", "Layouts directory for layout composition").action(async (options) => {
|
|
51
110
|
await devHandler(options);
|
|
52
111
|
});
|
|
53
|
-
program.command("build").description("Build for production").option("-o, --outDir <outDir>", "Output directory").action(async (options) => {
|
|
54
|
-
await
|
|
112
|
+
program.command("build").description("Build for production").option("-o, --outDir <outDir>", "Output directory").option("-c, --css <path>", "CSS entry point for Vite processing").option("-l, --layoutsDir <path>", "Layouts directory for layout composition").action(async (options) => {
|
|
113
|
+
const fileConfig = await loadConfig(process.cwd());
|
|
114
|
+
const resolved = await resolveConfig(fileConfig, {
|
|
115
|
+
outDir: options.outDir,
|
|
116
|
+
css: options.css,
|
|
117
|
+
layoutsDir: options.layoutsDir
|
|
118
|
+
});
|
|
119
|
+
const mergedOptions = {};
|
|
120
|
+
const outDirValue = options.outDir ?? resolved.build?.outDir;
|
|
121
|
+
if (outDirValue !== void 0) mergedOptions.outDir = outDirValue;
|
|
122
|
+
const cssValue = options.css ?? (typeof resolved.css === "string" ? resolved.css : resolved.css?.[0]);
|
|
123
|
+
if (cssValue !== void 0) mergedOptions.css = cssValue;
|
|
124
|
+
const layoutsDirValue = options.layoutsDir ?? resolved.layoutsDir;
|
|
125
|
+
if (layoutsDirValue !== void 0) mergedOptions.layoutsDir = layoutsDirValue;
|
|
126
|
+
await buildHandler(mergedOptions);
|
|
55
127
|
});
|
|
56
|
-
program.command("start").description("Start production server").option("-p, --port <port>", "Port number", "3000").action(async (options) => {
|
|
57
|
-
await
|
|
128
|
+
program.command("start").description("Start production server").option("-p, --port <port>", "Port number", "3000").option("-h, --host <host>", "Host address").option("-c, --css <path>", "CSS entry point for Vite processing").option("-l, --layoutsDir <path>", "Layouts directory for layout composition").action(async (options) => {
|
|
129
|
+
const fileConfig = await loadConfig(process.cwd());
|
|
130
|
+
const resolved = await resolveConfig(fileConfig, {
|
|
131
|
+
port: options.port ? parseInt(options.port, 10) : void 0,
|
|
132
|
+
host: options.host,
|
|
133
|
+
css: options.css,
|
|
134
|
+
layoutsDir: options.layoutsDir
|
|
135
|
+
});
|
|
136
|
+
const mergedOptions = {
|
|
137
|
+
port: options.port ?? (resolved.dev?.port ? String(resolved.dev.port) : "3000")
|
|
138
|
+
};
|
|
139
|
+
const hostValue = options.host ?? resolved.dev?.host;
|
|
140
|
+
if (hostValue !== void 0) mergedOptions.host = hostValue;
|
|
141
|
+
const cssValue = options.css ?? (typeof resolved.css === "string" ? resolved.css : resolved.css?.[0]);
|
|
142
|
+
if (cssValue !== void 0) mergedOptions.css = cssValue;
|
|
143
|
+
const layoutsDirValue = options.layoutsDir ?? resolved.layoutsDir;
|
|
144
|
+
if (layoutsDirValue !== void 0) mergedOptions.layoutsDir = layoutsDirValue;
|
|
145
|
+
await startHandler(mergedOptions);
|
|
58
146
|
});
|
|
59
147
|
return program;
|
|
60
148
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -57,10 +57,17 @@ interface PageModule {
|
|
|
57
57
|
default: CompiledProgram | PageExportFunction;
|
|
58
58
|
getStaticPaths?: () => Promise<StaticPathsResult> | StaticPathsResult;
|
|
59
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Single path entry from getStaticPaths
|
|
62
|
+
*/
|
|
63
|
+
interface StaticPathEntry {
|
|
64
|
+
/** Route parameters for this path */
|
|
65
|
+
params: Record<string, string>;
|
|
66
|
+
/** Optional data to inject as __pathData in importData */
|
|
67
|
+
data?: unknown;
|
|
68
|
+
}
|
|
60
69
|
interface StaticPathsResult {
|
|
61
|
-
paths:
|
|
62
|
-
params: Record<string, string>;
|
|
63
|
-
}>;
|
|
70
|
+
paths: StaticPathEntry[];
|
|
64
71
|
}
|
|
65
72
|
/**
|
|
66
73
|
* Constela configuration
|
|
@@ -81,14 +88,22 @@ interface DevServerOptions {
|
|
|
81
88
|
host?: string;
|
|
82
89
|
routesDir?: string;
|
|
83
90
|
publicDir?: string;
|
|
91
|
+
/** Layouts directory for layout composition */
|
|
92
|
+
layoutsDir?: string;
|
|
93
|
+
/** CSS entry point(s) for Vite middleware processing */
|
|
94
|
+
css?: string | string[];
|
|
84
95
|
}
|
|
85
96
|
/**
|
|
86
97
|
* Build options
|
|
87
98
|
*/
|
|
88
99
|
interface BuildOptions {
|
|
89
|
-
outDir?: string;
|
|
90
|
-
routesDir?: string;
|
|
91
|
-
|
|
100
|
+
outDir?: string | undefined;
|
|
101
|
+
routesDir?: string | undefined;
|
|
102
|
+
publicDir?: string | undefined;
|
|
103
|
+
layoutsDir?: string | undefined;
|
|
104
|
+
/** CSS entry point(s) for Vite middleware processing */
|
|
105
|
+
css?: string | string[] | undefined;
|
|
106
|
+
target?: 'node' | 'edge' | undefined;
|
|
92
107
|
}
|
|
93
108
|
|
|
94
109
|
/**
|
|
@@ -188,12 +203,13 @@ declare function resolveStaticFile(pathname: string, publicDir: string): StaticF
|
|
|
188
203
|
interface BuildResult {
|
|
189
204
|
outDir: string;
|
|
190
205
|
routes: string[];
|
|
206
|
+
generatedFiles: string[];
|
|
191
207
|
}
|
|
192
208
|
/**
|
|
193
209
|
* Build application for production
|
|
194
210
|
*
|
|
195
211
|
* @param options - Build options
|
|
196
|
-
* @returns BuildResult with outDir and
|
|
212
|
+
* @returns BuildResult with outDir, discovered routes, and generated files
|
|
197
213
|
*/
|
|
198
214
|
declare function build(options?: BuildOptions): Promise<BuildResult>;
|
|
199
215
|
|
|
@@ -506,4 +522,4 @@ declare class DataLoader {
|
|
|
506
522
|
getCacheSize(): number;
|
|
507
523
|
}
|
|
508
524
|
|
|
509
|
-
export { type APIContext, type APIModule, type BuildOptions, type ComponentDef$1 as ComponentDef, type ConstelaConfig, DataLoader, type DevServerOptions, type GenerateStaticPagesOptions, type GlobResult, type LayoutInfo, LayoutResolver, type MDXToConstelaOptions, type MdxGlobResult, type Middleware, type MiddlewareContext, type MiddlewareNext, type PageExportFunction, type PageModule, type ScannedLayout, type ScannedRoute, type StaticFileResult, type StaticPath, type StaticPathsProvider, type StaticPathsResult, build, createAPIHandler, createAdapter, createDevServer, createMiddlewareChain, filePathToPattern, generateStaticPages, generateStaticPaths, getMimeType, isPageExportFunction, isPathSafe, loadApi, loadComponentDefinitions, loadFile, loadGlob, loadLayout, mdxContentToNode, mdxToConstela, resolveLayout, resolvePageExport, resolveStaticFile, scanLayouts, scanRoutes, transformCsv, transformMdx, transformYaml };
|
|
525
|
+
export { type APIContext, type APIModule, type BuildOptions, type ComponentDef$1 as ComponentDef, type ConstelaConfig, DataLoader, type DevServerOptions, type GenerateStaticPagesOptions, type GlobResult, type LayoutInfo, LayoutResolver, type MDXToConstelaOptions, type MdxGlobResult, type Middleware, type MiddlewareContext, type MiddlewareNext, type PageExportFunction, type PageModule, type ScannedLayout, type ScannedRoute, type StaticFileResult, type StaticPath, type StaticPathEntry, type StaticPathsProvider, type StaticPathsResult, build, createAPIHandler, createAdapter, createDevServer, createMiddlewareChain, filePathToPattern, generateStaticPages, generateStaticPaths, getMimeType, isPageExportFunction, isPathSafe, loadApi, loadComponentDefinitions, loadFile, loadGlob, loadLayout, mdxContentToNode, mdxToConstela, resolveLayout, resolvePageExport, resolveStaticFile, scanLayouts, scanRoutes, transformCsv, transformMdx, transformYaml };
|