@jay-framework/stack-server-build 0.24.2 → 0.24.4
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 +23 -4
- package/dist/index.js +68 -22
- package/package.json +13 -13
package/dist/index.d.ts
CHANGED
|
@@ -58,6 +58,17 @@ interface LoadedPageParts {
|
|
|
58
58
|
/** Script tags with jay-script="allow" to include in SSR output */
|
|
59
59
|
scripts?: JayHtmlScript[];
|
|
60
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Resolve the browser hydration import path for a route (DL#182).
|
|
63
|
+
*
|
|
64
|
+
* SSR loads `route.compPath` (which is `./tools` for devOnly plugin routes, `.` otherwise); the
|
|
65
|
+
* browser must never load those server bundles. Prefer the explicit `clientCompPath` resolved from
|
|
66
|
+
* the plugin's `./client` export. Fall back to the legacy `index.js`→`index.client.js` rewrite only
|
|
67
|
+
* for NPM plugin routes (`componentExport` set) that carry no `clientCompPath` — note this rewrite
|
|
68
|
+
* silently no-ops for a devOnly `compPath` ending in `tools.js`, which is the bug DL#182 fixes.
|
|
69
|
+
* Local (project) components hydrate directly from `compPath`.
|
|
70
|
+
*/
|
|
71
|
+
declare function resolveClientImportPath(route: JayRoute): string;
|
|
61
72
|
interface LoadPagePartsOptions {
|
|
62
73
|
/**
|
|
63
74
|
* Path to pre-rendered jay-html file to use instead of the original.
|
|
@@ -124,6 +135,8 @@ interface ScriptFragments {
|
|
|
124
135
|
* Build the shared script fragments used by both client and hydration scripts.
|
|
125
136
|
*/
|
|
126
137
|
declare function buildScriptFragments(parts: DevServerPagePart[], clientInitData: Record<string, Record<string, any>>, projectInit: ProjectClientInitInfo | undefined, pluginInits: PluginClientInitInfo[], options: GenerateClientScriptOptions): ScriptFragments;
|
|
138
|
+
/** Dev-only: subscribe to jay:page-reload and reload when route prefix matches. */
|
|
139
|
+
declare function buildPageReloadHmrScript(): string;
|
|
127
140
|
/**
|
|
128
141
|
* Generate the automation wrapping code.
|
|
129
142
|
* @param mode - 'client' appends to DOM; 'hydrate' skips appendChild (DOM already present)
|
|
@@ -172,17 +185,23 @@ headTags?: HeadTag[],
|
|
|
172
185
|
/** Script tags with jay-script="allow" (DL#149) */
|
|
173
186
|
scripts?: JayHtmlScript[]): Promise<string>;
|
|
174
187
|
/**
|
|
175
|
-
* Generate a frozen page — pure SSR HTML
|
|
188
|
+
* Generate a frozen page — pure SSR HTML (DL#127).
|
|
176
189
|
*
|
|
177
190
|
* Uses the same server element module as generateSSRPageHtml, but:
|
|
178
191
|
* - No hydration script
|
|
179
|
-
* - No Vite client
|
|
180
192
|
* - No component runtime
|
|
181
193
|
* - Just rendered HTML + CSS
|
|
182
194
|
*
|
|
195
|
+
* Script policy:
|
|
196
|
+
* - Production / `format=fragment`: no client scripts
|
|
197
|
+
* - Dev full-page (`injectDevHmr: true`): minimal reload listener only — no hydration,
|
|
198
|
+
* automation, or freeze capture. Caller must run the result through `transformIndexHtml`.
|
|
199
|
+
*
|
|
183
200
|
* @param format - 'page' for full HTML document, 'fragment' for body-only (shadow DOM)
|
|
184
201
|
*/
|
|
185
|
-
declare function generateFrozenPageHtml(vite: ViteDevServer, jayHtmlContent: string, jayHtmlFilename: string, jayHtmlDir: string, viewState: object, buildFolder: string, projectRoot: string, routeDir: string, tsConfigFilePath?: string, sourceDir?: string, format?: 'page' | 'fragment', freezeName?: string
|
|
202
|
+
declare function generateFrozenPageHtml(vite: ViteDevServer, jayHtmlContent: string, jayHtmlFilename: string, jayHtmlDir: string, viewState: object, buildFolder: string, projectRoot: string, routeDir: string, tsConfigFilePath?: string, sourceDir?: string, format?: 'page' | 'fragment', freezeName?: string, options?: {
|
|
203
|
+
injectDevHmr?: boolean;
|
|
204
|
+
}): Promise<string>;
|
|
186
205
|
|
|
187
206
|
/**
|
|
188
207
|
* Action metadata loaded from .jay-action files.
|
|
@@ -661,4 +680,4 @@ declare class SlowRenderCache {
|
|
|
661
680
|
private scanAndDeleteCacheFiles;
|
|
662
681
|
}
|
|
663
682
|
|
|
664
|
-
export { type ActionDiscoveryOptions, type ActionDiscoveryResult, type ActionIndexEntry, type ActionMetadata, type ActionSchema, type CommandFlag, type CommandIndexEntry, type CommandMetadata, type ContextIndexEntry, type DevServerPagePart, type DiscoveredCommand, type GenerateClientScriptOptions, type HeadlessInstanceComponent, type LoadPagePartsOptions, type LoadedPageParts, type MaterializeContractsOptions, type MaterializeResult, type PluginActionDiscoveryOptions, type PluginContractEntry, type PluginWithAgentKit, type PluginWithSetup, type PluginsIndex, type PluginsIndexEntry, type ProjectClientInitInfo, type RouteIndexEntry, type ScriptFragments, type ServiceIndexEntry, SetupNeedsAnswerError, SlowRenderCache, type SlowRenderCacheEntry, type ViteSSRLoader, buildAutomationWrap, buildScriptFragments, clearServerElementCache, commandSchemaToFlags, discoverAllPluginActions, discoverAndRegisterActions, discoverPluginActions, discoverPluginCommands, discoverPluginsWithAgentKit, discoverPluginsWithSetup, executePluginAgentKit, executePluginCommand, executePluginSetup, generateClientScript, generateFrozenPageHtml, generatePromiseReconstruction, generateSSRPageHtml, headMetaToHeadTags, invalidateServerElementCache, listContracts, loadActionMetadata, loadPageParts, materializeContracts, parseActionMetadata, parseInputFromFlags, resolveActionMetadataPath, resolveViewStatePromises };
|
|
683
|
+
export { type ActionDiscoveryOptions, type ActionDiscoveryResult, type ActionIndexEntry, type ActionMetadata, type ActionSchema, type CommandFlag, type CommandIndexEntry, type CommandMetadata, type ContextIndexEntry, type DevServerPagePart, type DiscoveredCommand, type GenerateClientScriptOptions, type HeadlessInstanceComponent, type LoadPagePartsOptions, type LoadedPageParts, type MaterializeContractsOptions, type MaterializeResult, type PluginActionDiscoveryOptions, type PluginContractEntry, type PluginWithAgentKit, type PluginWithSetup, type PluginsIndex, type PluginsIndexEntry, type ProjectClientInitInfo, type RouteIndexEntry, type ScriptFragments, type ServiceIndexEntry, SetupNeedsAnswerError, SlowRenderCache, type SlowRenderCacheEntry, type ViteSSRLoader, buildAutomationWrap, buildPageReloadHmrScript, buildScriptFragments, clearServerElementCache, commandSchemaToFlags, discoverAllPluginActions, discoverAndRegisterActions, discoverPluginActions, discoverPluginCommands, discoverPluginsWithAgentKit, discoverPluginsWithSetup, executePluginAgentKit, executePluginCommand, executePluginSetup, generateClientScript, generateFrozenPageHtml, generatePromiseReconstruction, generateSSRPageHtml, headMetaToHeadTags, invalidateServerElementCache, listContracts, loadActionMetadata, loadPageParts, materializeContracts, parseActionMetadata, parseInputFromFlags, resolveActionMetadataPath, resolveClientImportPath, resolveViewStatePromises };
|
package/dist/index.js
CHANGED
|
@@ -18,6 +18,11 @@ import * as fs from "node:fs";
|
|
|
18
18
|
import { createRequire as createRequire$1 } from "node:module";
|
|
19
19
|
import { isJayAction, isJayStreamAction, isJayCliCommand } from "@jay-framework/fullstack-component";
|
|
20
20
|
const require$3 = createRequire(import.meta.url);
|
|
21
|
+
function resolveClientImportPath(route) {
|
|
22
|
+
if (route.clientCompPath) return route.clientCompPath;
|
|
23
|
+
if (route.componentExport) return route.compPath.replace(/index\.js$/, "index.client.js");
|
|
24
|
+
return route.compPath;
|
|
25
|
+
}
|
|
21
26
|
async function loadPageParts(vite, route, pagesBase, projectBase, jayRollupConfig, options) {
|
|
22
27
|
const exists = await fs$1.access(route.compPath, fs$1.constants.F_OK).then(() => true).catch(() => false);
|
|
23
28
|
const parts = [];
|
|
@@ -30,7 +35,7 @@ async function loadPageParts(vite, route, pagesBase, projectBase, jayRollupConfi
|
|
|
30
35
|
`${route.compPath} does not export "${exportName}". The file exists but the expected export is missing — remove the file or add the export.`
|
|
31
36
|
);
|
|
32
37
|
} else {
|
|
33
|
-
const clientImportPath = route
|
|
38
|
+
const clientImportPath = resolveClientImportPath(route);
|
|
34
39
|
parts.push({
|
|
35
40
|
compDefinition: pageComponent,
|
|
36
41
|
clientImport: `import {${exportName}} from '${clientImportPath}'`,
|
|
@@ -315,7 +320,7 @@ function normalizeActionEntry(entry) {
|
|
|
315
320
|
if (typeof entry === "string") {
|
|
316
321
|
return { name: entry };
|
|
317
322
|
}
|
|
318
|
-
return { name: entry.name, action: entry.action };
|
|
323
|
+
return { name: entry.name, action: entry.action, devOnly: entry.devOnly };
|
|
319
324
|
}
|
|
320
325
|
function loadPluginManifest(pluginDir) {
|
|
321
326
|
const pluginYamlPath = path$1.join(pluginDir, "plugin.yaml");
|
|
@@ -397,6 +402,18 @@ ${clientParts.map((part) => " " + part.clientPart).join(",\n")}
|
|
|
397
402
|
slowViewStateDecl
|
|
398
403
|
};
|
|
399
404
|
}
|
|
405
|
+
function buildPageReloadHmrScript() {
|
|
406
|
+
return `
|
|
407
|
+
if (import.meta.hot) {
|
|
408
|
+
import.meta.hot.on('jay:page-reload', (data) => {
|
|
409
|
+
const prefix = data.routePrefix;
|
|
410
|
+
const pathname = window.location.pathname;
|
|
411
|
+
if (pathname === prefix || pathname.startsWith(prefix + '/')) {
|
|
412
|
+
window.location.reload();
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
}`;
|
|
416
|
+
}
|
|
400
417
|
function buildFreezeScript(routePattern) {
|
|
401
418
|
const routePatternLiteral = routePattern ? `'${routePattern}'` : "undefined";
|
|
402
419
|
return `
|
|
@@ -472,15 +489,7 @@ function buildFreezeScript(routePattern) {
|
|
|
472
489
|
}
|
|
473
490
|
|
|
474
491
|
// Targeted page reload: only reload if this page matches the changed route prefix
|
|
475
|
-
|
|
476
|
-
import.meta.hot.on('jay:page-reload', (data) => {
|
|
477
|
-
const prefix = data.routePrefix;
|
|
478
|
-
const pathname = window.location.pathname;
|
|
479
|
-
if (pathname === prefix || pathname.startsWith(prefix + '/')) {
|
|
480
|
-
window.location.reload();
|
|
481
|
-
}
|
|
482
|
-
});
|
|
483
|
-
}`;
|
|
492
|
+
${buildPageReloadHmrScript()}`;
|
|
484
493
|
}
|
|
485
494
|
function buildAutomationWrap(options, mode) {
|
|
486
495
|
const { enableAutomation = true, slowViewState } = options;
|
|
@@ -719,7 +728,7 @@ ${titleTag}${headExtras ? headExtras + "\n" : ""} </head>
|
|
|
719
728
|
</body>
|
|
720
729
|
</html>`;
|
|
721
730
|
}
|
|
722
|
-
async function generateFrozenPageHtml(vite, jayHtmlContent, jayHtmlFilename, jayHtmlDir, viewState, buildFolder, projectRoot, routeDir, tsConfigFilePath, sourceDir, format = "page", freezeName) {
|
|
731
|
+
async function generateFrozenPageHtml(vite, jayHtmlContent, jayHtmlFilename, jayHtmlDir, viewState, buildFolder, projectRoot, routeDir, tsConfigFilePath, sourceDir, format = "page", freezeName, options) {
|
|
723
732
|
const jayHtmlPath = path__default.join(jayHtmlDir, jayHtmlFilename);
|
|
724
733
|
let cached = serverModuleCache.get(jayHtmlPath);
|
|
725
734
|
if (!cached) {
|
|
@@ -765,6 +774,9 @@ ${ssrHtml}`;
|
|
|
765
774
|
const cssLink = cached.cssHref ? ` <link rel="stylesheet" href="${cached.cssHref}" />` : "";
|
|
766
775
|
const headExtras = [cssLink, frozenHeadTagsHtml].filter((_) => _).join("\n");
|
|
767
776
|
const label = freezeName ? ` — ${freezeName}` : "";
|
|
777
|
+
const devHmrScript = options?.injectDevHmr === true ? `
|
|
778
|
+
<script type="module">${buildPageReloadHmrScript()}
|
|
779
|
+
<\/script>` : "";
|
|
768
780
|
return `<!doctype html>
|
|
769
781
|
<html lang="en">
|
|
770
782
|
<head>
|
|
@@ -788,7 +800,7 @@ ${headExtras ? headExtras + "\n" : ""} <style>
|
|
|
788
800
|
</style>
|
|
789
801
|
</head>
|
|
790
802
|
<body>
|
|
791
|
-
<div id="target">${ssrHtml}</div
|
|
803
|
+
<div id="target">${ssrHtml}</div>${devHmrScript}
|
|
792
804
|
</body>
|
|
793
805
|
</html>`;
|
|
794
806
|
}
|
|
@@ -1169,9 +1181,18 @@ async function registerNpmPluginActions(packageName, pluginConfig, pluginDir, re
|
|
|
1169
1181
|
} else {
|
|
1170
1182
|
pluginModule = await import(packageName);
|
|
1171
1183
|
}
|
|
1184
|
+
let toolsModule;
|
|
1185
|
+
const loadToolsModule = async () => {
|
|
1186
|
+
if (!toolsModule) {
|
|
1187
|
+
const toolsEntry = `${packageName}/tools`;
|
|
1188
|
+
toolsModule = viteServer ? await viteServer.ssrLoadModule(toolsEntry) : await import(toolsEntry);
|
|
1189
|
+
}
|
|
1190
|
+
return toolsModule;
|
|
1191
|
+
};
|
|
1172
1192
|
for (const entry of pluginConfig.actions) {
|
|
1173
|
-
const { name: actionName, action: actionPath } = normalizeActionEntry(entry);
|
|
1174
|
-
const
|
|
1193
|
+
const { name: actionName, action: actionPath, devOnly } = normalizeActionEntry(entry);
|
|
1194
|
+
const sourceModule = devOnly ? await loadToolsModule() : pluginModule;
|
|
1195
|
+
const actionExport = sourceModule[actionName];
|
|
1175
1196
|
if (actionExport && isJayAction(actionExport)) {
|
|
1176
1197
|
registry.register(actionExport);
|
|
1177
1198
|
const registeredName = actionExport.actionName;
|
|
@@ -1243,6 +1264,13 @@ async function discoverPluginActions(pluginPath, projectRoot, registry = actionR
|
|
|
1243
1264
|
return [];
|
|
1244
1265
|
}
|
|
1245
1266
|
}
|
|
1267
|
+
const resolveLocalToolsModulePath = () => {
|
|
1268
|
+
for (const candidate of ["tools.ts", "tools.js"]) {
|
|
1269
|
+
const candidatePath = path.join(pluginPath, candidate);
|
|
1270
|
+
if (fs.existsSync(candidatePath)) return candidatePath;
|
|
1271
|
+
}
|
|
1272
|
+
return null;
|
|
1273
|
+
};
|
|
1246
1274
|
try {
|
|
1247
1275
|
let pluginModule;
|
|
1248
1276
|
if (viteServer) {
|
|
@@ -1250,9 +1278,23 @@ async function discoverPluginActions(pluginPath, projectRoot, registry = actionR
|
|
|
1250
1278
|
} else {
|
|
1251
1279
|
pluginModule = await import(modulePath);
|
|
1252
1280
|
}
|
|
1281
|
+
let toolsModule;
|
|
1282
|
+
const loadToolsModule = async () => {
|
|
1283
|
+
if (toolsModule) return toolsModule;
|
|
1284
|
+
const toolsPath = resolveLocalToolsModulePath();
|
|
1285
|
+
if (!toolsPath) {
|
|
1286
|
+
getLogger().warn(
|
|
1287
|
+
`[Actions] Plugin "${pluginName}" declares a devOnly action but has no tools.ts/tools.js module`
|
|
1288
|
+
);
|
|
1289
|
+
return void 0;
|
|
1290
|
+
}
|
|
1291
|
+
toolsModule = viteServer ? await viteServer.ssrLoadModule(toolsPath) : await import(toolsPath);
|
|
1292
|
+
return toolsModule;
|
|
1293
|
+
};
|
|
1253
1294
|
for (const entry of pluginConfig.actions) {
|
|
1254
|
-
const { name: actionName, action: actionPath } = normalizeActionEntry(entry);
|
|
1255
|
-
const
|
|
1295
|
+
const { name: actionName, action: actionPath, devOnly } = normalizeActionEntry(entry);
|
|
1296
|
+
const sourceModule = devOnly ? await loadToolsModule() : pluginModule;
|
|
1297
|
+
const actionExport = sourceModule?.[actionName];
|
|
1256
1298
|
if (actionExport && isJayAction(actionExport)) {
|
|
1257
1299
|
registry.register(actionExport);
|
|
1258
1300
|
const registeredName = actionExport.actionName;
|
|
@@ -1878,10 +1920,11 @@ async function loadCommandHandler(command, viteServer) {
|
|
|
1878
1920
|
module = await import(modulePath);
|
|
1879
1921
|
}
|
|
1880
1922
|
} else {
|
|
1923
|
+
const toolsEntry = `${command.packageName}/tools`;
|
|
1881
1924
|
if (viteServer) {
|
|
1882
|
-
module = await viteServer.ssrLoadModule(
|
|
1925
|
+
module = await viteServer.ssrLoadModule(toolsEntry);
|
|
1883
1926
|
} else {
|
|
1884
|
-
module = await import(
|
|
1927
|
+
module = await import(toolsEntry);
|
|
1885
1928
|
}
|
|
1886
1929
|
}
|
|
1887
1930
|
for (const [, exported] of Object.entries(module)) {
|
|
@@ -2015,14 +2058,15 @@ async function loadHandler(plugin, handlerName, viteServer) {
|
|
|
2015
2058
|
`Handler "${handlerName}" not found in "${plugin.pluginPath}". Available exports: ${Object.keys(module).join(", ")}`
|
|
2016
2059
|
);
|
|
2017
2060
|
} else {
|
|
2061
|
+
const toolsEntry = `${plugin.packageName}/tools`;
|
|
2018
2062
|
if (viteServer) {
|
|
2019
|
-
module = await viteServer.ssrLoadModule(
|
|
2063
|
+
module = await viteServer.ssrLoadModule(toolsEntry);
|
|
2020
2064
|
} else {
|
|
2021
|
-
module = await import(
|
|
2065
|
+
module = await import(toolsEntry);
|
|
2022
2066
|
}
|
|
2023
2067
|
if (typeof module[handlerName] !== "function") {
|
|
2024
2068
|
throw new Error(
|
|
2025
|
-
`Handler "${handlerName}" not found as export in "${
|
|
2069
|
+
`Handler "${handlerName}" not found as export in "${toolsEntry}". Available exports: ${Object.keys(module).join(", ")}`
|
|
2026
2070
|
);
|
|
2027
2071
|
}
|
|
2028
2072
|
return module[handlerName];
|
|
@@ -2264,6 +2308,7 @@ export {
|
|
|
2264
2308
|
SetupNeedsAnswerError,
|
|
2265
2309
|
SlowRenderCache,
|
|
2266
2310
|
buildAutomationWrap,
|
|
2311
|
+
buildPageReloadHmrScript,
|
|
2267
2312
|
buildScriptFragments,
|
|
2268
2313
|
clearServerElementCache,
|
|
2269
2314
|
commandSchemaToFlags,
|
|
@@ -2289,5 +2334,6 @@ export {
|
|
|
2289
2334
|
parseActionMetadata,
|
|
2290
2335
|
parseInputFromFlags,
|
|
2291
2336
|
resolveActionMetadataPath,
|
|
2337
|
+
resolveClientImportPath,
|
|
2292
2338
|
resolveViewStatePromises
|
|
2293
2339
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jay-framework/stack-server-build",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.4",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.mts",
|
|
@@ -24,21 +24,21 @@
|
|
|
24
24
|
"test:watch": "vitest"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@jay-framework/compiler-jay-html": "^0.24.
|
|
28
|
-
"@jay-framework/compiler-shared": "^0.24.
|
|
29
|
-
"@jay-framework/component": "^0.24.
|
|
30
|
-
"@jay-framework/fullstack-component": "^0.24.
|
|
31
|
-
"@jay-framework/logger": "^0.24.
|
|
32
|
-
"@jay-framework/runtime": "^0.24.
|
|
33
|
-
"@jay-framework/ssr-runtime": "^0.24.
|
|
34
|
-
"@jay-framework/stack-route-scanner": "^0.24.
|
|
35
|
-
"@jay-framework/stack-server-runtime": "^0.24.
|
|
36
|
-
"@jay-framework/view-state-merge": "^0.24.
|
|
27
|
+
"@jay-framework/compiler-jay-html": "^0.24.4",
|
|
28
|
+
"@jay-framework/compiler-shared": "^0.24.4",
|
|
29
|
+
"@jay-framework/component": "^0.24.4",
|
|
30
|
+
"@jay-framework/fullstack-component": "^0.24.4",
|
|
31
|
+
"@jay-framework/logger": "^0.24.4",
|
|
32
|
+
"@jay-framework/runtime": "^0.24.4",
|
|
33
|
+
"@jay-framework/ssr-runtime": "^0.24.4",
|
|
34
|
+
"@jay-framework/stack-route-scanner": "^0.24.4",
|
|
35
|
+
"@jay-framework/stack-server-runtime": "^0.24.4",
|
|
36
|
+
"@jay-framework/view-state-merge": "^0.24.4",
|
|
37
37
|
"yaml": "^2.3.4"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@jay-framework/dev-environment": "^0.24.
|
|
41
|
-
"@jay-framework/rollup-plugin": "^0.24.
|
|
40
|
+
"@jay-framework/dev-environment": "^0.24.4",
|
|
41
|
+
"@jay-framework/rollup-plugin": "^0.24.4",
|
|
42
42
|
"@types/node": "^22.15.21",
|
|
43
43
|
"rimraf": "^5.0.5",
|
|
44
44
|
"tsup": "^8.0.1",
|