@vmz/core 0.1.10 → 0.1.11

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.
@@ -7,7 +7,7 @@ import fs from 'node:fs';
7
7
  import { readdir } from 'node:fs/promises';
8
8
  import path from 'node:path';
9
9
  import { pathToFileURL } from 'node:url';
10
- import { componentEntriesFromDeployment, mergeExplicitComponentEntries, readDeploymentDocument, } from './deployment-registry.js';
10
+ import { componentEntriesFromDeployment, dedupeComponentEntriesByTag, mergeExplicitComponentEntries, readDeploymentDocument, } from './deployment-registry.js';
11
11
  export { DEPLOYMENT_SCHEMA, readDeploymentDocument, componentEntriesFromDeployment, collectDependsOnClosure, dedupeComponentEntriesByTag, mergeExplicitComponentEntries, loadComponentEntries, importAndRegisterComponentEntries, bootstrapComponentRegistry, } from './deployment-registry.js';
12
12
  export { createRenderHost } from './render-host.js';
13
13
  /**
@@ -16,14 +16,23 @@ export { createRenderHost } from './render-host.js';
16
16
  * @returns {Promise<Array<{ name: string, entry: string, chunkId?: string }>>}
17
17
  */
18
18
  export async function listClientComponents(dir, opts = {}) {
19
- const deployment = readDeploymentDocument(dir, { strict: opts.strict === true });
19
+ const strict = opts.strict === true;
20
+ const deployment = readDeploymentDocument(dir, { strict });
20
21
  if (deployment) {
21
- return componentEntriesFromDeployment(deployment).map((e) => ({
22
+ return dedupeComponentEntriesByTag(componentEntriesFromDeployment(deployment).map((e) => ({
23
+ chunkId: e.chunkId,
24
+ name: e.name,
25
+ entry: e.entry,
26
+ source: e.source,
27
+ }))).map((e) => ({
22
28
  name: e.name,
23
29
  entry: e.entry,
24
30
  chunkId: e.chunkId,
25
31
  }));
26
32
  }
33
+ if (strict) {
34
+ throw new Error(`vmz: missing vmz-deployment.json under ${dir} (strict deployment mode)`);
35
+ }
27
36
  const folder = path.join(dir, 'components');
28
37
  /** @type {string[]} */
29
38
  let files = [];
@@ -48,14 +57,23 @@ export async function listClientComponents(dir, opts = {}) {
48
57
  * @returns {Array<{ name: string, entry: string, chunkId?: string }>}
49
58
  */
50
59
  export function listClientComponentsSync(dir, opts = {}) {
51
- const deployment = readDeploymentDocument(dir, { strict: opts.strict === true });
60
+ const strict = opts.strict === true;
61
+ const deployment = readDeploymentDocument(dir, { strict });
52
62
  if (deployment) {
53
- return componentEntriesFromDeployment(deployment).map((e) => ({
63
+ return dedupeComponentEntriesByTag(componentEntriesFromDeployment(deployment).map((e) => ({
64
+ chunkId: e.chunkId,
65
+ name: e.name,
66
+ entry: e.entry,
67
+ source: e.source,
68
+ }))).map((e) => ({
54
69
  name: e.name,
55
70
  entry: e.entry,
56
71
  chunkId: e.chunkId,
57
72
  }));
58
73
  }
74
+ if (strict) {
75
+ throw new Error(`vmz: missing vmz-deployment.json under ${dir} (strict deployment mode)`);
76
+ }
59
77
  const folder = path.join(dir, 'components');
60
78
  /** @type {string[]} */
61
79
  let files = [];
@@ -22,7 +22,7 @@ import http from 'node:http';
22
22
  import { createRequire, registerHooks } from 'node:module';
23
23
  import path from 'node:path';
24
24
  import { fileURLToPath, pathToFileURL } from 'node:url';
25
- import { registerComponents, renderToStream, renderToString } from './vmz-dom.js';
25
+ import { createRenderHost } from './render-host.js';
26
26
  import { listClientComponents } from './list-client-components.js';
27
27
  import { handleNodeRequest, setRoutes, setServerModuleResolver } from './vmz-runtime.js';
28
28
  const require = createRequire(import.meta.url);
@@ -76,6 +76,8 @@ if (isDev) {
76
76
  }
77
77
  /** @type {number} */
78
78
  let reloadToken = Date.now();
79
+ /** @type {Awaited<ReturnType<typeof createRenderHost>> | null} */
80
+ let ssrRenderHost = null;
79
81
  /** @type {string | null} Correlatable build id from vmz dev (Living §12.8). */
80
82
  let lastDevBuildId = null;
81
83
  /** @type {Array<{ chunkId: string, pageRel: string, segs: ReturnType<typeof parseChunkSegments> }>} */
@@ -503,9 +505,17 @@ async function* emitPageHtml(Page, chunkId, eventOnlyShell, props = {}, opts = {
503
505
  const pageDocMeta = resolvePageDocumentMeta(Page);
504
506
  const prevLocaleHint = globalThis.__vmzLocaleIdHint;
505
507
  globalThis.__vmzLocaleIdHint = localeId;
508
+ if (!ssrRenderHost) {
509
+ ssrRenderHost = await createRenderHost(distDir, {
510
+ strictDeployment: !isDev,
511
+ preload: 'none',
512
+ cacheBust: reloadToken,
513
+ });
514
+ }
515
+ await ssrRenderHost.ensureComponents([chunkId, ...layoutChain]);
506
516
  let bodyHtml = '';
507
517
  try {
508
- for await (const chunk of renderToStream(Page, props, { signal })) {
518
+ for await (const chunk of ssrRenderHost.renderToStream(Page, props, { signal })) {
509
519
  if (signal?.aborted)
510
520
  return;
511
521
  bodyHtml += chunk;
@@ -517,7 +527,7 @@ async function* emitPageHtml(Page, chunkId, eventOnlyShell, props = {}, opts = {
517
527
  const Layout = await loadPageCtor(layoutChain[i]);
518
528
  if (!Layout)
519
529
  continue;
520
- bodyHtml = await renderToString(Layout, {}, { signal, slotHtml: bodyHtml });
530
+ bodyHtml = await ssrRenderHost.renderToString(Layout, {}, { signal, slotHtml: bodyHtml });
521
531
  if (signal?.aborted)
522
532
  return;
523
533
  }
@@ -709,28 +719,18 @@ async function softReload(opts = {}) {
709
719
  catch {
710
720
  localeArtifact = null;
711
721
  }
712
- const componentEntries = await listClientComponents(distDir);
722
+ const componentEntries = await listClientComponents(distDir, { strict: !isDev });
723
+ ssrRenderHost = await createRenderHost(distDir, {
724
+ strictDeployment: !isDev,
725
+ preload: 'none',
726
+ cacheBust: nextToken,
727
+ });
713
728
  const nextCatalog = await listPageClientFiles(distDir);
714
729
  if (!nextCatalog.length) {
715
730
  throw new Error(`vmz serve: no pages/**/*.client.js in ${distDir}`);
716
731
  }
717
- /** @type {Record<string, any>} */
718
- const components = {};
719
732
  /** @type {Map<string, any>} */
720
733
  const nextCtors = new Map();
721
- const affectedNames = new Set(affected
722
- .map((c) => String(c))
723
- .filter((c) => c.startsWith('components/') || !c.includes('/'))
724
- .map((c) => c.split('/').pop())
725
- .filter(Boolean));
726
- for (const entry of componentEntries) {
727
- if (islandHmr && affectedNames.size > 0 && !affectedNames.has(entry.name)) {
728
- continue;
729
- }
730
- const href = bustUrl(pathToFileURL(path.join(distDir, entry.entry)).href);
731
- const mod = await import(href);
732
- components[entry.name] = mod.default;
733
- }
734
734
  if (!islandHmr) {
735
735
  const pagesToLoad = reloadAllPages ? nextCatalog : nextCatalog.filter((p) => pageNeedsReload(p.chunkId, affected));
736
736
  for (const p of pagesToLoad) {
@@ -758,9 +758,6 @@ async function softReload(opts = {}) {
758
758
  }
759
759
  }
760
760
  }
761
- if (Object.keys(components).length) {
762
- registerComponents(components);
763
- }
764
761
  const indexChunk = pageCatalog.find((p) => p.chunkId === 'pages/index')?.chunkId || pageCatalog[0].chunkId;
765
762
  const resumeEntries = await loadPageResumeEntries(distDir, indexChunk);
766
763
  const styleMeta = await loadDeploymentStyle(distDir);
package/dist/server.js CHANGED
@@ -231,7 +231,9 @@ export async function handleNodeRequest(req, res, opts = {}) {
231
231
  if (verb === 'GET' && opts.distDir) {
232
232
  const nodePath = await import('node:path');
233
233
  const { readFile, stat } = await import('node:fs/promises');
234
- const file = await resolveDistStatic(opts.distDir, url.pathname, nodePath, stat);
234
+ const file = await resolveDistStatic(opts.distDir, url.pathname, nodePath, stat, {
235
+ cookieHeader: String(req.headers.cookie || ''),
236
+ });
235
237
  const hasSsr = typeof opts.renderPageStream === 'function' ||
236
238
  typeof opts.renderPage === 'function' ||
237
239
  typeof opts.renderIndexStream === 'function' ||
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vmz/core",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "type": "module",
5
5
  "description": "VMZ production runtime core — DOM / SSR / HTTP / WriteBarrier (no compiler)",
6
6
  "exports": {