@jay-framework/dev-server 0.12.0 → 0.13.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.
Files changed (2) hide show
  1. package/dist/index.js +144 -11
  2. package/package.json +14 -14
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ import { getLogger, getDevLogger } from "@jay-framework/logger";
15
15
  import { createRequire as createRequire$1 } from "node:module";
16
16
  import * as fs from "node:fs";
17
17
  import { scanRoutes, routeToExpressRoute } from "@jay-framework/stack-route-scanner";
18
- import { discoverPluginsWithInit, sortPluginsByDependencies, executePluginServerInits, runInitCallbacks, actionRegistry, discoverAndRegisterActions, discoverAllPluginActions, runShutdownCallbacks, clearLifecycleCallbacks, clearServiceRegistry, clearClientInitData, DevSlowlyChangingPhase, SlowRenderCache, preparePluginClientInits, getServiceRegistry, materializeContracts, loadPageParts, renderFastChangingData, slowRenderInstances, generateClientScript, getClientInitData, resolveServices } from "@jay-framework/stack-server-runtime";
18
+ import { discoverPluginsWithInit, sortPluginsByDependencies, executePluginServerInits, runInitCallbacks, actionRegistry, discoverAndRegisterActions, discoverAllPluginActions, runShutdownCallbacks, clearLifecycleCallbacks, clearServiceRegistry, clearClientInitData, DevSlowlyChangingPhase, SlowRenderCache, preparePluginClientInits, getServiceRegistry, materializeContracts, loadPageParts, renderFastChangingData, validateForEachInstances, slowRenderInstances, generateClientScript, getClientInitData, resolveServices } from "@jay-framework/stack-server-runtime";
19
19
  import fs$1 from "node:fs/promises";
20
20
  import { pathToFileURL } from "node:url";
21
21
  const s$1 = createRequire(import.meta.url), e$1 = s$1("typescript"), c$1 = new Proxy(e$1, {
@@ -1401,9 +1401,7 @@ async function createViteForCli(options) {
1401
1401
  ignored: ["**/build/**"]
1402
1402
  }
1403
1403
  },
1404
- plugins: [
1405
- ...jayStackCompiler({ tsConfigFilePath })
1406
- ],
1404
+ plugins: [...jayStackCompiler({ tsConfigFilePath })],
1407
1405
  appType: "custom",
1408
1406
  root: projectRoot,
1409
1407
  ssr: {
@@ -1864,7 +1862,12 @@ function filterPluginsForPage(allPluginClientInits, allPluginsWithInit, usedPack
1864
1862
  pluginsByPackage.set(plugin.packageName, plugin);
1865
1863
  }
1866
1864
  const expandedPackages = new Set(usedPackages);
1867
- const toProcess = [...usedPackages];
1865
+ for (const plugin of allPluginsWithInit) {
1866
+ if (plugin.global) {
1867
+ expandedPackages.add(plugin.packageName);
1868
+ }
1869
+ }
1870
+ const toProcess = [...expandedPackages];
1868
1871
  while (toProcess.length > 0) {
1869
1872
  const packageName = toProcess.pop();
1870
1873
  const plugin = pluginsByPackage.get(packageName);
@@ -2001,10 +2004,11 @@ async function handleCachedRequest(vite, route, options, cachedEntry, pageParams
2001
2004
  let fastViewState = renderedFast.rendered;
2002
2005
  let fastCarryForward = renderedFast.carryForward;
2003
2006
  const instancePhaseData = cachedEntry.carryForward?.__instances;
2004
- if (instancePhaseData && pagePartsResult.val.headlessInstanceComponents.length > 0) {
2007
+ const headlessComps = pagePartsResult.val.headlessInstanceComponents;
2008
+ if (instancePhaseData && headlessComps.length > 0) {
2005
2009
  const instanceFastResult = await renderFastChangingDataForInstances(
2006
2010
  instancePhaseData,
2007
- pagePartsResult.val.headlessInstanceComponents
2011
+ headlessComps
2008
2012
  );
2009
2013
  if (instanceFastResult) {
2010
2014
  fastViewState = {
@@ -2016,6 +2020,20 @@ async function handleCachedRequest(vite, route, options, cachedEntry, pageParams
2016
2020
  __headlessInstances: instanceFastResult.carryForwards
2017
2021
  };
2018
2022
  }
2023
+ if (instancePhaseData.forEachInstances && instancePhaseData.forEachInstances.length > 0) {
2024
+ const forEachResult = await renderFastChangingDataForForEachInstances(
2025
+ instancePhaseData.forEachInstances,
2026
+ headlessComps,
2027
+ fastViewState
2028
+ );
2029
+ if (forEachResult) {
2030
+ const existingHeadless = fastViewState.__headlessInstances || {};
2031
+ fastViewState = {
2032
+ ...fastViewState,
2033
+ __headlessInstances: { ...existingHeadless, ...forEachResult }
2034
+ };
2035
+ }
2036
+ }
2019
2037
  }
2020
2038
  await sendResponse(
2021
2039
  vite,
@@ -2075,7 +2093,20 @@ async function handlePreRenderRequest(vite, route, options, slowlyPhase, slowRen
2075
2093
  timing?.end();
2076
2094
  return;
2077
2095
  }
2078
- const carryForward = preRenderResult.instancePhaseData ? { ...renderedSlowly.carryForward, __instances: preRenderResult.instancePhaseData } : renderedSlowly.carryForward;
2096
+ let instancePhaseDataForCache = preRenderResult.instancePhaseData;
2097
+ if (instancePhaseDataForCache && preRenderResult.forEachInstances) {
2098
+ instancePhaseDataForCache = {
2099
+ ...instancePhaseDataForCache,
2100
+ forEachInstances: preRenderResult.forEachInstances
2101
+ };
2102
+ } else if (preRenderResult.forEachInstances) {
2103
+ instancePhaseDataForCache = {
2104
+ discovered: [],
2105
+ carryForwards: {},
2106
+ forEachInstances: preRenderResult.forEachInstances
2107
+ };
2108
+ }
2109
+ const carryForward = instancePhaseDataForCache ? { ...renderedSlowly.carryForward, __instances: instancePhaseDataForCache } : renderedSlowly.carryForward;
2079
2110
  const preRenderedPath = await slowRenderCache.set(
2080
2111
  route.jayHtmlPath,
2081
2112
  pageParams,
@@ -2120,10 +2151,11 @@ async function handlePreRenderRequest(vite, route, options, slowlyPhase, slowRen
2120
2151
  let fastViewState = renderedFast.rendered;
2121
2152
  let fastCarryForward = renderedFast.carryForward;
2122
2153
  const instancePhaseData = carryForward?.__instances;
2123
- if (instancePhaseData && pagePartsResult.val.headlessInstanceComponents.length > 0) {
2154
+ const headlessComps = pagePartsResult.val.headlessInstanceComponents;
2155
+ if (instancePhaseData && headlessComps.length > 0) {
2124
2156
  const instanceFastResult = await renderFastChangingDataForInstances(
2125
2157
  instancePhaseData,
2126
- pagePartsResult.val.headlessInstanceComponents
2158
+ headlessComps
2127
2159
  );
2128
2160
  if (instanceFastResult) {
2129
2161
  fastViewState = {
@@ -2135,6 +2167,20 @@ async function handlePreRenderRequest(vite, route, options, slowlyPhase, slowRen
2135
2167
  __headlessInstances: instanceFastResult.carryForwards
2136
2168
  };
2137
2169
  }
2170
+ if (instancePhaseData.forEachInstances && instancePhaseData.forEachInstances.length > 0) {
2171
+ const forEachResult = await renderFastChangingDataForForEachInstances(
2172
+ instancePhaseData.forEachInstances,
2173
+ headlessComps,
2174
+ fastViewState
2175
+ );
2176
+ if (forEachResult) {
2177
+ const existingHeadless = fastViewState.__headlessInstances || {};
2178
+ fastViewState = {
2179
+ ...fastViewState,
2180
+ __headlessInstances: { ...existingHeadless, ...forEachResult }
2181
+ };
2182
+ }
2183
+ }
2138
2184
  }
2139
2185
  await sendResponse(
2140
2186
  vite,
@@ -2191,10 +2237,26 @@ async function handleDirectRequest(vite, route, options, slowlyPhase, pageParams
2191
2237
  }
2192
2238
  let instanceViewStates;
2193
2239
  let instancePhaseDataForFast;
2240
+ let forEachInstancesForFast;
2194
2241
  const headlessInstanceComponents = pagePartsResult.val.headlessInstanceComponents ?? [];
2195
2242
  if (headlessInstanceComponents.length > 0) {
2196
2243
  const jayHtmlContent = await fs$1.readFile(route.jayHtmlPath, "utf-8");
2197
2244
  const discoveryResult = discoverHeadlessInstances(jayHtmlContent);
2245
+ if (discoveryResult.forEachInstances.length > 0) {
2246
+ const validationErrors = validateForEachInstances(
2247
+ discoveryResult.forEachInstances,
2248
+ headlessInstanceComponents
2249
+ );
2250
+ if (validationErrors.length > 0) {
2251
+ getLogger().error(
2252
+ `[SlowRender] ForEach instance validation failed: ${validationErrors.join(", ")}`
2253
+ );
2254
+ res.status(500).end(validationErrors.join("\n"));
2255
+ timing?.end();
2256
+ return;
2257
+ }
2258
+ forEachInstancesForFast = discoveryResult.forEachInstances;
2259
+ }
2198
2260
  if (discoveryResult.instances.length > 0) {
2199
2261
  const slowResult = await slowRenderInstances(
2200
2262
  discoveryResult.instances,
@@ -2228,6 +2290,20 @@ async function handleDirectRequest(vite, route, options, slowlyPhase, pageParams
2228
2290
  }
2229
2291
  }
2230
2292
  }
2293
+ if (forEachInstancesForFast && renderedFast.kind === "PhaseOutput") {
2294
+ const forEachResult = await renderFastChangingDataForForEachInstances(
2295
+ forEachInstancesForFast,
2296
+ headlessInstanceComponents,
2297
+ { ...renderedSlowly.rendered, ...renderedFast.rendered }
2298
+ );
2299
+ if (forEachResult) {
2300
+ if (!instanceViewStates)
2301
+ instanceViewStates = {};
2302
+ for (const [coordKey, fastVS] of Object.entries(forEachResult)) {
2303
+ instanceViewStates[coordKey] = fastVS;
2304
+ }
2305
+ }
2306
+ }
2231
2307
  timing?.recordFastRender(Date.now() - fastStart);
2232
2308
  if (renderedFast.kind !== "PhaseOutput") {
2233
2309
  handleOtherResponseCodes(res, renderedFast);
@@ -2332,9 +2408,23 @@ async function preRenderJayHtml(route, slowViewState, headlessContracts, headles
2332
2408
  }
2333
2409
  let preRenderedJayHtml = result.val.preRenderedJayHtml;
2334
2410
  let instancePhaseData;
2411
+ let forEachInstances;
2335
2412
  if (headlessInstanceComponents.length > 0) {
2336
2413
  const discoveryResult = discoverHeadlessInstances(preRenderedJayHtml);
2337
2414
  preRenderedJayHtml = discoveryResult.preRenderedJayHtml;
2415
+ if (discoveryResult.forEachInstances.length > 0) {
2416
+ const validationErrors = validateForEachInstances(
2417
+ discoveryResult.forEachInstances,
2418
+ headlessInstanceComponents
2419
+ );
2420
+ if (validationErrors.length > 0) {
2421
+ getLogger().error(
2422
+ `[SlowRender] ForEach instance validation failed: ${validationErrors.join(", ")}`
2423
+ );
2424
+ return void 0;
2425
+ }
2426
+ forEachInstances = discoveryResult.forEachInstances;
2427
+ }
2338
2428
  if (discoveryResult.instances.length > 0) {
2339
2429
  const slowResult = await slowRenderInstances(
2340
2430
  discoveryResult.instances,
@@ -2358,7 +2448,7 @@ async function preRenderJayHtml(route, slowViewState, headlessContracts, headles
2358
2448
  }
2359
2449
  }
2360
2450
  }
2361
- return { preRenderedJayHtml, instancePhaseData };
2451
+ return { preRenderedJayHtml, instancePhaseData, forEachInstances };
2362
2452
  }
2363
2453
  async function renderFastChangingDataForInstances(instancePhaseData, headlessInstanceComponents) {
2364
2454
  const componentByContractName = /* @__PURE__ */ new Map();
@@ -2389,6 +2479,49 @@ async function renderFastChangingDataForInstances(instancePhaseData, headlessIns
2389
2479
  }
2390
2480
  return hasResults ? { viewStates, carryForwards } : void 0;
2391
2481
  }
2482
+ async function renderFastChangingDataForForEachInstances(forEachInstances, headlessInstanceComponents, mergedViewState) {
2483
+ const componentByContractName = /* @__PURE__ */ new Map();
2484
+ for (const comp of headlessInstanceComponents) {
2485
+ componentByContractName.set(comp.contractName, comp);
2486
+ }
2487
+ const viewStates = {};
2488
+ let hasResults = false;
2489
+ for (const instance of forEachInstances) {
2490
+ const comp = componentByContractName.get(instance.contractName);
2491
+ if (!comp)
2492
+ continue;
2493
+ const items = resolvePathValue(mergedViewState, instance.forEachPath);
2494
+ if (!Array.isArray(items))
2495
+ continue;
2496
+ for (const item of items) {
2497
+ const trackByValue = String(item[instance.trackBy]);
2498
+ const props = {};
2499
+ for (const [propName, binding] of Object.entries(instance.propBindings)) {
2500
+ props[propName] = resolveBinding(String(binding), item);
2501
+ }
2502
+ if (comp.compDefinition.fastRender) {
2503
+ const services = resolveServices(comp.compDefinition.services);
2504
+ const fastResult = await comp.compDefinition.fastRender(props, ...services);
2505
+ if (fastResult.kind === "PhaseOutput") {
2506
+ const coord = [trackByValue, instance.coordinateSuffix].toString();
2507
+ viewStates[coord] = fastResult.rendered;
2508
+ hasResults = true;
2509
+ }
2510
+ }
2511
+ }
2512
+ }
2513
+ return hasResults ? viewStates : void 0;
2514
+ }
2515
+ function resolvePathValue(obj, path2) {
2516
+ return path2.split(".").reduce((current, segment) => current?.[segment], obj);
2517
+ }
2518
+ function resolveBinding(binding, item) {
2519
+ const match = binding.match(/^\{(.+)\}$/);
2520
+ if (match) {
2521
+ return String(item[match[1]] ?? "");
2522
+ }
2523
+ return binding;
2524
+ }
2392
2525
  async function materializeDynamicContracts(projectRootFolder, buildFolder, viteServer) {
2393
2526
  try {
2394
2527
  const services = getServiceRegistry();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jay-framework/dev-server",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/index.js",
@@ -22,22 +22,22 @@
22
22
  "test:watch": "vitest"
23
23
  },
24
24
  "dependencies": {
25
- "@jay-framework/compiler-jay-stack": "^0.12.0",
26
- "@jay-framework/compiler-shared": "^0.12.0",
27
- "@jay-framework/component": "^0.12.0",
28
- "@jay-framework/fullstack-component": "^0.12.0",
29
- "@jay-framework/logger": "^0.12.0",
30
- "@jay-framework/runtime": "^0.12.0",
31
- "@jay-framework/stack-client-runtime": "^0.12.0",
32
- "@jay-framework/stack-route-scanner": "^0.12.0",
33
- "@jay-framework/stack-server-runtime": "^0.12.0",
34
- "@jay-framework/view-state-merge": "^0.12.0",
25
+ "@jay-framework/compiler-jay-stack": "^0.13.0",
26
+ "@jay-framework/compiler-shared": "^0.13.0",
27
+ "@jay-framework/component": "^0.13.0",
28
+ "@jay-framework/fullstack-component": "^0.13.0",
29
+ "@jay-framework/logger": "^0.13.0",
30
+ "@jay-framework/runtime": "^0.13.0",
31
+ "@jay-framework/stack-client-runtime": "^0.13.0",
32
+ "@jay-framework/stack-route-scanner": "^0.13.0",
33
+ "@jay-framework/stack-server-runtime": "^0.13.0",
34
+ "@jay-framework/view-state-merge": "^0.13.0",
35
35
  "vite": "^5.0.11"
36
36
  },
37
37
  "devDependencies": {
38
- "@jay-framework/dev-environment": "^0.12.0",
39
- "@jay-framework/jay-cli": "^0.12.0",
40
- "@jay-framework/stack-client-runtime": "^0.12.0",
38
+ "@jay-framework/dev-environment": "^0.13.0",
39
+ "@jay-framework/jay-cli": "^0.13.0",
40
+ "@jay-framework/stack-client-runtime": "^0.13.0",
41
41
  "@types/express": "^5.0.2",
42
42
  "@types/node": "^22.15.21",
43
43
  "nodemon": "^3.0.3",