@jay-framework/production-server 0.22.2 → 0.23.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.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { B as BuildOptions, R as RouteManifest, a as RouteEntry } from './serve-index-lg6huJYm.js';
2
- export { A as ActionEntry, e as ArtifactStore, c as BuildMetadata, C as CacheEntry, F as FilesystemArtifactStore, I as InstanceEntry, M as MatchResult, d as PageModule, P as PluginEntry, n as PreImportedPlugin, b as RouteSegment, S as ServerElementModule, g as fetchActionRequest, f as fetchPageRequest, j as fetchStaticFile, k as initializeServices, l as initializeServicesFromModules, i as isActionRequest, m as matchRequest, r as registerActionsFromManifest, h as registerActionsFromModules } from './serve-index-lg6huJYm.js';
1
+ import { B as BuildOptions, R as RouteManifest, a as RouteEntry } from './serve-index-XSavezh8.js';
2
+ export { A as ActionEntry, e as ArtifactStore, c as BuildMetadata, C as CacheEntry, F as FilesystemArtifactStore, I as InstanceEntry, M as MatchResult, d as PageModule, P as PluginEntry, n as PreImportedPlugin, b as RouteSegment, S as ServerElementModule, g as fetchActionRequest, f as fetchPageRequest, j as fetchStaticFile, k as initializeServices, l as initializeServicesFromModules, i as isActionRequest, m as matchRequest, r as registerActionsFromManifest, h as registerActionsFromModules } from './serve-index-XSavezh8.js';
3
3
  import '@jay-framework/ssr-runtime';
4
4
  import '@jay-framework/compiler-shared';
5
5
  import '@jay-framework/stack-server-runtime';
package/dist/index.js CHANGED
@@ -6,8 +6,8 @@ import path from "node:path";
6
6
  import fs from "node:fs/promises";
7
7
  import { createRequire } from "node:module";
8
8
  import { DevSlowlyChangingPhase, slowRenderInstances, scanPlugins, runLoadParams, parseCookies } from "@jay-framework/stack-server-runtime";
9
- import { l as loadProductionPageParts, g as buildPagePartsConfig, d as initializeServices, r as registerActionsFromManifest, i as isActionRequest, a as fetchActionRequest, c as fetchStaticFile, m as matchRequest, f as fetchPageRequest, F as FilesystemArtifactStore } from "./init-services-zmGSxSck.js";
10
- import { e, b } from "./init-services-zmGSxSck.js";
9
+ import { l as loadProductionPageParts, g as buildPagePartsConfig, d as initializeServices, r as registerActionsFromManifest, i as isActionRequest, a as fetchActionRequest, c as fetchStaticFile, m as matchRequest, f as fetchPageRequest, F as FilesystemArtifactStore } from "./init-services-AtDV4X1i.js";
10
+ import { e, b } from "./init-services-AtDV4X1i.js";
11
11
  import crypto, { createHash } from "node:crypto";
12
12
  import fs$1 from "node:fs";
13
13
  import { jayRuntime } from "@jay-framework/vite-plugin";
@@ -250,31 +250,27 @@ async function buildInstance(route, params, pageModule, ctx, routeServerElementP
250
250
  ])
251
251
  ];
252
252
  const pagePartsConfigPath = path.join(backendInstanceDir, "page-parts.json");
253
- try {
254
- await fs.access(pagePartsConfigPath);
255
- } catch {
256
- const exportName = route.componentExport || "page";
257
- let pageServerModule = "";
258
- let pageIsPlugin = false;
259
- if (route.compPath) {
260
- if (route.componentExport) {
261
- pageServerModule = route.packageName || route.compPath;
262
- pageIsPlugin = true;
263
- } else {
264
- const relativePath = path.relative(ctx.projectRoot, route.compPath);
265
- pageServerModule = relativePath.replace(/^src\//, "server/").replace(/\.ts$/, ".js").replace(/\[/g, "_").replace(/\]/g, "_");
266
- }
253
+ const exportName = route.componentExport || "page";
254
+ let pageServerModule = "";
255
+ let pageIsPlugin = false;
256
+ if (route.compPath) {
257
+ if (route.componentExport) {
258
+ pageServerModule = route.packageName || route.compPath;
259
+ pageIsPlugin = true;
260
+ } else {
261
+ const relativePath = path.relative(ctx.projectRoot, route.compPath);
262
+ pageServerModule = relativePath.replace(/^src\//, "server/").replace(/\.ts$/, ".js").replace(/\[/g, "_").replace(/\]/g, "_");
267
263
  }
268
- const config = buildPagePartsConfig(
269
- pageParts,
270
- pageServerModule,
271
- exportName,
272
- ctx.backendDir,
273
- pageIsPlugin
274
- );
275
- await fs.writeFile(pagePartsConfigPath, JSON.stringify(config, null, 2));
276
- logger.info(`[Build] Page parts config: ${routeDir}/page-parts.json`);
277
264
  }
265
+ const config = buildPagePartsConfig(
266
+ pageParts,
267
+ pageServerModule,
268
+ exportName,
269
+ ctx.backendDir,
270
+ pageIsPlugin
271
+ );
272
+ await fs.writeFile(pagePartsConfigPath, JSON.stringify(config, null, 2));
273
+ logger.info(`[Build] Page parts config: ${routeDir}/page-parts.json`);
278
274
  const slowPhase = new DevSlowlyChangingPhase();
279
275
  const slowResult = await slowPhase.runSlowlyForPage(
280
276
  params,
@@ -377,7 +373,8 @@ function buildRouteEntry(route, serverModulePath) {
377
373
  segments: convertSegments(route.segments),
378
374
  serverModule: serverModulePath,
379
375
  componentExport: route.componentExport,
380
- instances: []
376
+ instances: [],
377
+ ...route.devOnly && { devOnly: true }
381
378
  };
382
379
  }
383
380
  async function discoverActions(actionPaths, serverOutputDir, buildDir, projectRoot) {
@@ -467,9 +464,12 @@ async function scanPluginRoutes(projectRoot, projectRoutes) {
467
464
  jayHtmlPath,
468
465
  compPath,
469
466
  componentExport,
470
- packageName: plugin.packageName
467
+ packageName: plugin.packageName,
468
+ ...route.devOnly === true && { devOnly: true }
471
469
  });
472
- logger.info(`[Routes] Plugin "${plugin.manifest.name}" provides route ${route.path}`);
470
+ logger.info(
471
+ `[Routes] Plugin "${plugin.manifest.name}" provides route ${route.path}${route.devOnly ? " (dev-only)" : ""}`
472
+ );
473
473
  }
474
474
  }
475
475
  return pluginRoutes;
@@ -558,14 +558,11 @@ async function compileServerElement(jayHtmlContent, jayHtmlFilename, jayHtmlDir,
558
558
  const css = parsedJayFile.css;
559
559
  if (css) {
560
560
  cssImports = extractCssImportUrls(css);
561
- const cssFilename = path.basename(outputPath, ".server-element.js") + ".css";
562
- const cssPath = path.join(outputDir, cssFilename);
563
- if (minifyCss) {
564
- const minified = await transform(css, { loader: "css", minify: true });
565
- await fs.writeFile(cssPath, minified.code, "utf-8");
566
- } else {
567
- await fs.writeFile(cssPath, css, "utf-8");
568
- }
561
+ const cssContent = minifyCss ? (await transform(css, { loader: "css", minify: true })).code : css;
562
+ const hash = createHash("sha256").update(cssContent).digest("hex").slice(0, 8);
563
+ const baseName = path.basename(outputPath, ".server-element.js");
564
+ const cssFilename = `${baseName}-${hash}.css`;
565
+ await fs.writeFile(path.join(outputDir, cssFilename), cssContent, "utf-8");
569
566
  cssFile = cssFilename;
570
567
  }
571
568
  getLogger().info(`[Build] Compiled server element: ${path.basename(outputPath)}`);
@@ -1134,8 +1131,9 @@ async function buildVersion(options) {
1134
1131
  continue;
1135
1132
  const paramParts = [];
1136
1133
  for (const part of partsWithLoadParams) {
1137
- const fn = part.compDefinition.loadParams;
1138
- if (!loadParamsCache.has(fn)) {
1134
+ const propsKey = JSON.stringify(part.headlessProps ?? {});
1135
+ const cacheKey = `${part.key ?? ""}:${propsKey}`;
1136
+ if (!loadParamsCache.has(cacheKey)) {
1139
1137
  logger.important(`[Build] Loading params for ${route.rawRoute}...`);
1140
1138
  const partParams = [];
1141
1139
  let batchIndex = 0;
@@ -1146,9 +1144,9 @@ async function buildVersion(options) {
1146
1144
  logger.important(`[Build] ...${partParams.length} params so far`);
1147
1145
  }
1148
1146
  }
1149
- loadParamsCache.set(fn, partParams);
1147
+ loadParamsCache.set(cacheKey, partParams);
1150
1148
  }
1151
- const cached = loadParamsCache.get(fn);
1149
+ const cached = loadParamsCache.get(cacheKey);
1152
1150
  const keys = new Set(cached.flatMap((p) => Object.keys(p)));
1153
1151
  paramParts.push({ keys, values: cached });
1154
1152
  }
@@ -64,9 +64,14 @@ async function loadProductionPageParts(route, pageModule, jayHtmlContent, projec
64
64
  } else {
65
65
  modulePath = module;
66
66
  }
67
- const resolvedModulePath = isLocalModule ? modulePath : require2.resolve(module, { paths: [dirName] });
68
- const headlessModule = await import(resolvedModulePath);
69
- const headlessCompDef = headlessModule[name];
67
+ let headlessCompDef;
68
+ if (headlessImport.structural) {
69
+ continue;
70
+ } else {
71
+ const resolvedModulePath = isLocalModule ? modulePath : require2.resolve(module, { paths: [dirName] });
72
+ const headlessModule = await import(resolvedModulePath);
73
+ headlessCompDef = headlessModule[name];
74
+ }
70
75
  if (headlessImport.key) {
71
76
  const clientModulePath = isLocalModule ? path.resolve(dirName, module) : `${module}/client`;
72
77
  const ci = headlessImport.contract ? { contractName: headlessImport.contract.name, metadata: headlessImport.metadata } : void 0;
@@ -78,18 +83,22 @@ async function loadProductionPageParts(route, pageModule, jayHtmlContent, projec
78
83
  contractInfo: ci,
79
84
  headlessProps: headlessImport.headlessProps
80
85
  });
81
- keyedPartModules.push({
82
- key: headlessImport.key,
83
- modulePath: clientModulePath,
84
- exportName: name
85
- });
86
+ const hasClientComp = !!headlessCompDef?.fastRender || !!headlessCompDef?.hasInteractive;
87
+ if (!headlessImport.structural && hasClientComp) {
88
+ keyedPartModules.push({
89
+ key: headlessImport.key,
90
+ modulePath: clientModulePath,
91
+ exportName: name
92
+ });
93
+ }
86
94
  headlessModuleInfos.push({
87
95
  modulePath,
88
96
  exportName: name,
89
97
  isLocal: isLocalModule,
90
98
  key: headlessImport.key,
91
99
  contractInfo: ci,
92
- headlessProps: headlessImport.headlessProps
100
+ headlessProps: headlessImport.headlessProps,
101
+ structural: headlessImport.structural
93
102
  });
94
103
  }
95
104
  if (!headlessImport.key && headlessImport.contract) {
@@ -103,7 +112,8 @@ async function loadProductionPageParts(route, pageModule, jayHtmlContent, projec
103
112
  exportName: name,
104
113
  isLocal: isLocalModule,
105
114
  contractName: headlessImport.contractName,
106
- propNames: headlessImport.contract.props?.map((p) => p.name) ?? []
115
+ propNames: headlessImport.contract.props?.map((p) => p.name) ?? [],
116
+ structural: headlessImport.structural
107
117
  });
108
118
  }
109
119
  }
@@ -163,11 +173,12 @@ function buildPagePartsConfig(pageParts, pageServerModule, pageExportName, build
163
173
  for (const info of pageParts.headlessModuleInfos) {
164
174
  if (info.contractName) {
165
175
  instanceComponents.push({
166
- modulePath: info.isLocal ? path.relative(buildDir, info.modulePath) : info.modulePath,
176
+ modulePath: info.structural ? "" : info.isLocal ? path.relative(buildDir, info.modulePath) : info.modulePath,
167
177
  exportName: info.exportName,
168
178
  source: info.isLocal ? "local" : "npm",
169
179
  contractName: info.contractName,
170
- propNames: info.propNames ?? []
180
+ propNames: info.propNames ?? [],
181
+ ...info.structural ? { structural: true } : {}
171
182
  });
172
183
  }
173
184
  }
@@ -207,10 +218,12 @@ async function loadPagePartsFromConfig(configPath, artifacts) {
207
218
  }
208
219
  const headlessInstanceComponents = [];
209
220
  for (const entry of config.instanceComponents) {
210
- const mod = await importModule(entry);
211
221
  const serveTimeContract = {
212
222
  props: entry.propNames.map((name) => ({ name }))
213
223
  };
224
+ if (entry.structural)
225
+ continue;
226
+ const mod = await importModule(entry);
214
227
  headlessInstanceComponents.push({
215
228
  contractName: entry.contractName,
216
229
  compDefinition: mod[entry.exportName] ?? mod.default,
@@ -424,6 +437,10 @@ async function fetchPageRequest(match, manifest, requestUrl, artifacts, staticBa
424
437
  fastViewState,
425
438
  route.trackByMap || {}
426
439
  );
440
+ fullViewState.__jay = {
441
+ params: match.params,
442
+ url: { path: requestUrl.pathname }
443
+ };
427
444
  const headTagSources = [];
428
445
  const slowHeadTags = cf.__slowHeadTags;
429
446
  if (slowHeadTags)
@@ -436,7 +453,14 @@ async function fetchPageRequest(match, manifest, requestUrl, artifacts, staticBa
436
453
  const headTags = headTagSources.length > 0 ? mergeHeadTags(headTagSources) : [];
437
454
  const hasCustomTitle = headTags.some((t) => t.tag?.toLowerCase() === "title");
438
455
  const titleTag = hasCustomTitle ? "" : " <title>Vite + TS</title>\n";
439
- const headTagsHtml = headTags.length > 0 ? serializeHeadTags(headTags) + "\n" : "";
456
+ const preconnectTags = headTags.filter(
457
+ (t) => t.tag === "link" && t.attrs?.rel === "preconnect"
458
+ );
459
+ const otherHeadTags = headTags.filter(
460
+ (t) => !(t.tag === "link" && t.attrs?.rel === "preconnect")
461
+ );
462
+ const preconnectHtml = preconnectTags.length > 0 ? serializeHeadTags(preconnectTags) + "\n" : "";
463
+ const headTagsHtml = otherHeadTags.length > 0 ? serializeHeadTags(otherHeadTags) + "\n" : "";
440
464
  const serverElementPath = route.serverElementPath || instance.serverElementPath;
441
465
  const tLoadStart = Date.now();
442
466
  const serverElement = await artifacts.loadServerElement(serverElementPath);
@@ -463,7 +487,7 @@ async function fetchPageRequest(match, manifest, requestUrl, artifacts, staticBa
463
487
  <head>
464
488
  <meta charset="UTF-8" />
465
489
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
466
- ${titleTag}${[cssPreload, cssImportPreloads].filter(Boolean).map((l) => l + "\n").join(
490
+ ${titleTag}${[preconnectHtml, cssPreload, cssImportPreloads].filter(Boolean).map((l) => l + "\n").join(
467
491
  ""
468
492
  )} <script type="importmap">${JSON.stringify({ imports: importMap })}<\/script>
469
493
  ${headParts}
@@ -36,6 +36,8 @@ interface RouteEntry {
36
36
  instances: InstanceEntry[];
37
37
  isPlugin?: boolean;
38
38
  pluginName?: string;
39
+ /** When true, dev-server tooling route (future: excluded from production builds). */
40
+ devOnly?: boolean;
39
41
  }
40
42
  interface InstanceEntry {
41
43
  params: Record<string, string>;
@@ -85,6 +87,7 @@ interface PagePartsConfigEntry {
85
87
  modulePath: string;
86
88
  exportName: string;
87
89
  source: 'npm' | 'local';
90
+ structural?: boolean;
88
91
  }
89
92
  interface PagePartsConfig {
90
93
  parts: Array<PagePartsConfigEntry & {
@@ -1,4 +1,4 @@
1
- export { e as ArtifactStore, C as CacheEntry, F as FilesystemArtifactStore, I as InstanceEntry, M as MatchResult, n as PreImportedPlugin, a as RouteEntry, R as RouteManifest, S as ServerElementModule, g as fetchActionRequest, f as fetchPageRequest, j as fetchStaticFile, k as initializeServices, l as initializeServicesFromModules, i as isActionRequest, m as matchRequest, r as registerActionsFromManifest, h as registerActionsFromModules } from './serve-index-lg6huJYm.js';
1
+ export { e as ArtifactStore, C as CacheEntry, F as FilesystemArtifactStore, I as InstanceEntry, M as MatchResult, n as PreImportedPlugin, a as RouteEntry, R as RouteManifest, S as ServerElementModule, g as fetchActionRequest, f as fetchPageRequest, j as fetchStaticFile, k as initializeServices, l as initializeServicesFromModules, i as isActionRequest, m as matchRequest, r as registerActionsFromManifest, h as registerActionsFromModules } from './serve-index-XSavezh8.js';
2
2
  import '@jay-framework/ssr-runtime';
3
3
  import '@jay-framework/compiler-shared';
4
4
  import '@jay-framework/stack-server-runtime';
@@ -1,4 +1,4 @@
1
- import { F, a, f, c, d, e, i, m, r, b } from "./init-services-zmGSxSck.js";
1
+ import { F, a, f, c, d, e, i, m, r, b } from "./init-services-AtDV4X1i.js";
2
2
  import "node:fs/promises";
3
3
  import "node:path";
4
4
  import "@jay-framework/stack-server-runtime";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jay-framework/production-server",
3
- "version": "0.22.2",
3
+ "version": "0.23.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -30,20 +30,20 @@
30
30
  "test:watch": "vitest"
31
31
  },
32
32
  "dependencies": {
33
- "@jay-framework/compiler-jay-html": "^0.22.2",
34
- "@jay-framework/compiler-jay-stack": "^0.22.2",
35
- "@jay-framework/compiler-shared": "^0.22.2",
36
- "@jay-framework/fullstack-component": "^0.22.2",
37
- "@jay-framework/logger": "^0.22.2",
38
- "@jay-framework/ssr-runtime": "^0.22.2",
39
- "@jay-framework/stack-route-scanner": "^0.22.2",
40
- "@jay-framework/stack-server-runtime": "^0.22.2",
41
- "@jay-framework/view-state-merge": "^0.22.2",
42
- "@jay-framework/vite-plugin": "^0.22.2",
33
+ "@jay-framework/compiler-jay-html": "^0.23.0",
34
+ "@jay-framework/compiler-jay-stack": "^0.23.0",
35
+ "@jay-framework/compiler-shared": "^0.23.0",
36
+ "@jay-framework/fullstack-component": "^0.23.0",
37
+ "@jay-framework/logger": "^0.23.0",
38
+ "@jay-framework/ssr-runtime": "^0.23.0",
39
+ "@jay-framework/stack-route-scanner": "^0.23.0",
40
+ "@jay-framework/stack-server-runtime": "^0.23.0",
41
+ "@jay-framework/view-state-merge": "^0.23.0",
42
+ "@jay-framework/vite-plugin": "^0.23.0",
43
43
  "vite": "^5.0.11"
44
44
  },
45
45
  "devDependencies": {
46
- "@jay-framework/dev-environment": "^0.22.2",
46
+ "@jay-framework/dev-environment": "^0.23.0",
47
47
  "@types/node": "^22.15.21",
48
48
  "rimraf": "^5.0.5",
49
49
  "tsup": "^8.0.1",