arcway 0.1.23 → 0.1.25

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.
@@ -28,7 +28,8 @@ import {
28
28
  import { createClientBuildContext } from './build-client.js';
29
29
  import { buildCssBundle } from './build-css.js';
30
30
  import { resolveFonts } from './fonts.js';
31
- import { buildHmrRuntimeBundle } from './hmr.js';
31
+ import { buildHmrRuntimeBundle, diffClientMetafiles } from './hmr.js';
32
+ import { syncViteHydrationEntries } from './vite-dev.js';
32
33
 
33
34
  // Dev-mode build context that defers per-page/layout/middleware server-bundle
34
35
  // compilation to first request. Startup is cheap: discover routes, build the
@@ -50,6 +51,7 @@ async function createLazyPagesContext(options) {
50
51
  const clientTarget = options.clientTarget ?? 'es2022';
51
52
  const minify = options.minify ?? false;
52
53
  const devMode = options.devMode ?? true;
54
+ const viteDev = options.viteDev ?? false;
53
55
  const esbuildImpl = options.esbuild ?? esbuild;
54
56
  // Cap per-context server-bundle concurrency so a request burst after a
55
57
  // cold start can't spawn N pages × M esbuild Go workers simultaneously.
@@ -63,6 +65,7 @@ async function createLazyPagesContext(options) {
63
65
 
64
66
  let disposed = false;
65
67
  let clientCtx = null;
68
+ let currentClientMetafile = null;
66
69
  let fontFaceCss;
67
70
  let fontPreloadHtml;
68
71
 
@@ -101,6 +104,13 @@ async function createLazyPagesContext(options) {
101
104
  { srcPath: path.resolve(m.filePath), built: false, stale: false },
102
105
  ]),
103
106
  ),
107
+ loadings: new Map(
108
+ loadings.map((l) => [
109
+ l.dirPath,
110
+ { srcPath: path.resolve(l.filePath) },
111
+ ]),
112
+ ),
113
+ stylesPath: stylesPath ? path.resolve(stylesPath) : null,
104
114
  version: 0,
105
115
  };
106
116
 
@@ -120,11 +130,46 @@ async function createLazyPagesContext(options) {
120
130
  events.emit(event, payload);
121
131
  }
122
132
 
133
+ function applyClientResult(clientResult) {
134
+ for (const entry of manifest.entries) {
135
+ const clientBundle = clientResult.bundles.get(entry.pattern);
136
+ const navBundle = clientResult.navBundles.get(entry.pattern);
137
+ if (clientBundle) entry.clientBundle = clientBundle;
138
+ if (navBundle) entry.navBundle = navBundle;
139
+ entry.layoutClientBundles = entry.layoutDirs
140
+ .map((d) => clientResult.layoutNavBundles.get(d))
141
+ .filter((v) => v !== undefined);
142
+ entry.loadingClientBundles = entry.loadingDirs
143
+ .map((d) => clientResult.loadingNavBundles.get(d))
144
+ .filter((v) => v !== undefined);
145
+ entry.sharedChunks = clientResult.entryChunks?.get(entry.pattern) ?? [];
146
+ entry.sharedCssChunks = clientResult.entryCssChunks?.get(entry.pattern) ?? [];
147
+ }
148
+ currentClientMetafile = clientResult.metafile ?? currentClientMetafile;
149
+ }
150
+
123
151
  // Client bundle + CSS + error pages + HMR runtime are built eagerly at
124
152
  // startup. They're shared across every request and their compilation cost
125
153
  // is bounded (a single esbuild.context for the client, one esbuild.transform
126
154
  // for CSS), so there's no win in deferring them.
127
155
  async function eagerSharedBuilds() {
156
+ if (viteDev) {
157
+ const [errorBundles] = await Promise.all([
158
+ buildErrorPageBundles(errorPages, outDir, serverTarget, {
159
+ rootDir,
160
+ devMode,
161
+ minify,
162
+ limit,
163
+ }),
164
+ syncViteHydrationEntries({ manifest, outDir }),
165
+ ]);
166
+ if (errorBundles.error) manifest.errorBundle = errorBundles.error;
167
+ if (errorBundles.notFound) manifest.notFoundBundle = errorBundles.notFound;
168
+ bumpVersion();
169
+ emit('update', { type: 'startup', version: manifest.version });
170
+ return { clientMetafile: null };
171
+ }
172
+
128
173
  clientCtx = await createClientBuildContext(
129
174
  pages,
130
175
  layouts,
@@ -151,20 +196,7 @@ async function createLazyPagesContext(options) {
151
196
  // Fold client bundle output into the manifest so renderPage() can find
152
197
  // navBundle / layoutClientBundles / shared chunks immediately, the same
153
198
  // as it would from a disk-backed prod manifest.
154
- for (const entry of manifest.entries) {
155
- const clientBundle = clientResult.bundles.get(entry.pattern);
156
- const navBundle = clientResult.navBundles.get(entry.pattern);
157
- if (clientBundle) entry.clientBundle = clientBundle;
158
- if (navBundle) entry.navBundle = navBundle;
159
- entry.layoutClientBundles = entry.layoutDirs
160
- .map((d) => clientResult.layoutNavBundles.get(d))
161
- .filter((v) => v !== undefined);
162
- entry.loadingClientBundles = entry.loadingDirs
163
- .map((d) => clientResult.loadingNavBundles.get(d))
164
- .filter((v) => v !== undefined);
165
- entry.sharedChunks = clientResult.entryChunks?.get(entry.pattern) ?? [];
166
- entry.sharedCssChunks = clientResult.entryCssChunks?.get(entry.pattern) ?? [];
167
- }
199
+ applyClientResult(clientResult);
168
200
  if (cssBundle) manifest.cssBundle = cssBundle;
169
201
  if (errorBundles.error) manifest.errorBundle = errorBundles.error;
170
202
  if (errorBundles.notFound) manifest.notFoundBundle = errorBundles.notFound;
@@ -314,13 +346,55 @@ async function createLazyPagesContext(options) {
314
346
  });
315
347
  }
316
348
 
317
- // Mark every manifest entry affected by a source change as stale. Does not
318
- // trigger rebuilds directly — the next `ensurePageBuilt()` call (driven by
319
- // an incoming request) handles the actual work. Structural changes
320
- // (add/remove files) are not handled here; the watcher will re-init the
321
- // context or extend the manifest in phase 5.
322
- function invalidate(filePath) {
349
+ function markAllEntriesStale() {
350
+ let touched = false;
351
+ const affected = { pages: [], layouts: [], middlewares: [] };
352
+ for (const entry of manifest.entries) {
353
+ if (!entry.stale || entry.built) {
354
+ entry.stale = true;
355
+ entry.built = false;
356
+ touched = true;
357
+ }
358
+ affected.pages.push(entry.pattern);
359
+ }
360
+ for (const [dirPath, layout] of manifest.layouts.entries()) {
361
+ if (!layout.stale || layout.built) {
362
+ layout.stale = true;
363
+ layout.built = false;
364
+ touched = true;
365
+ }
366
+ affected.layouts.push(dirPath);
367
+ }
368
+ for (const [dirPath, mw] of manifest.middlewares.entries()) {
369
+ if (!mw.stale || mw.built) {
370
+ mw.stale = true;
371
+ mw.built = false;
372
+ touched = true;
373
+ }
374
+ affected.middlewares.push(dirPath);
375
+ }
376
+ return { touched, affected };
377
+ }
378
+
379
+ function shouldInvalidateWholeTree(filePath, affected) {
380
+ if (
381
+ affected.pages.length > 0 ||
382
+ affected.layouts.length > 0 ||
383
+ affected.middlewares.length > 0
384
+ ) {
385
+ return false;
386
+ }
387
+ const rel = path.relative(rootDir, filePath).replace(/\\/g, '/');
388
+ if (!rel || rel.startsWith('..')) return false;
389
+ return /^(components|hooks|client|packages)\//.test(rel);
390
+ }
391
+
392
+ function markAffectedStale(filePath) {
323
393
  const affected = mapFileToAffected(filePath, manifest);
394
+ if (shouldInvalidateWholeTree(filePath, affected)) {
395
+ return markAllEntriesStale();
396
+ }
397
+
324
398
  let touched = false;
325
399
  for (const pattern of affected.pages) {
326
400
  const entry = findEntry(pattern);
@@ -346,6 +420,16 @@ async function createLazyPagesContext(options) {
346
420
  touched = true;
347
421
  }
348
422
  }
423
+ return { touched, affected };
424
+ }
425
+
426
+ // Mark every manifest entry affected by a source change as stale. Does not
427
+ // trigger rebuilds directly — the next `ensurePageBuilt()` call (driven by
428
+ // an incoming request) handles the actual work. Structural changes
429
+ // (add/remove files) are not handled here; the watcher will re-init the
430
+ // context or extend the manifest in phase 5.
431
+ function invalidate(filePath) {
432
+ const { touched, affected } = markAffectedStale(filePath);
349
433
  if (touched) {
350
434
  bumpVersion();
351
435
  emit('update', { type: 'invalidate', filePath, affected, version: manifest.version });
@@ -353,6 +437,87 @@ async function createLazyPagesContext(options) {
353
437
  return { touched, affected };
354
438
  }
355
439
 
440
+ let inFlightClientRefresh = null;
441
+
442
+ async function handleSourceChange(filePath) {
443
+ if (disposed) throw new Error('Lazy pages context is disposed');
444
+ const { touched, affected } = markAffectedStale(filePath);
445
+ if (!touched) return { touched: false, affected, hmr: null };
446
+ if (viteDev) {
447
+ bumpVersion();
448
+ emit('update', { type: 'invalidate', filePath, affected, version: manifest.version });
449
+ return { touched: true, affected, hmr: null };
450
+ }
451
+ if (inFlightClientRefresh) return inFlightClientRefresh;
452
+
453
+ const task = (async () => {
454
+ const previousMetafile = currentClientMetafile;
455
+ const previousCssBundle = manifest.cssBundle ?? null;
456
+ const timestamp = Date.now();
457
+
458
+ const [clientResult, cssBundle] = await Promise.all([
459
+ clientCtx?.rebuild() ?? Promise.resolve(null),
460
+ buildCssBundle(pagesDir, outDir, minify, stylesPath, fontFaceCss, rootDir),
461
+ ]);
462
+
463
+ if (clientResult) {
464
+ applyClientResult(clientResult);
465
+ }
466
+ if (cssBundle) manifest.cssBundle = cssBundle;
467
+
468
+ bumpVersion();
469
+ emit('update', { type: 'invalidate', filePath, affected, version: manifest.version });
470
+
471
+ let hmr = null;
472
+ if (clientResult && previousMetafile) {
473
+ const diff = diffClientMetafiles(previousMetafile, clientResult.metafile, outDir);
474
+ const modules = [...diff.changedHydrationBundles, ...diff.changedNavBundles];
475
+ const routeBundles = {};
476
+ for (const pattern of affected.pages) {
477
+ const entry = findEntry(pattern);
478
+ if (entry?.clientBundle) routeBundles[pattern] = entry.clientBundle;
479
+ }
480
+ if (diff.needsFullReload) {
481
+ hmr = { type: 'reload', timestamp };
482
+ emit('update', {
483
+ type: 'reload',
484
+ filePath,
485
+ reason: 'client-bundle-drift',
486
+ timestamp,
487
+ version: manifest.version,
488
+ });
489
+ } else if (modules.length > 0) {
490
+ hmr = { type: 'hmr-update', modules, routeBundles, timestamp };
491
+ emit('update', {
492
+ type: 'hmr-update',
493
+ filePath,
494
+ modules,
495
+ routeBundles,
496
+ timestamp,
497
+ version: manifest.version,
498
+ });
499
+ }
500
+ }
501
+
502
+ if (manifest.cssBundle) {
503
+ emit('update', {
504
+ type: 'css-update',
505
+ filePath,
506
+ cssBundle: manifest.cssBundle,
507
+ timestamp,
508
+ version: manifest.version,
509
+ });
510
+ }
511
+
512
+ return { touched: true, affected, hmr };
513
+ })().finally(() => {
514
+ inFlightClientRefresh = null;
515
+ });
516
+
517
+ inFlightClientRefresh = task;
518
+ return task;
519
+ }
520
+
356
521
  // ── Structural rediscovery ─────────────────────────────────────────────
357
522
  // `invalidate()` handles content edits to known files; `rediscover()`
358
523
  // handles add/delete of pages, layouts, and middlewares. Re-runs the same
@@ -385,6 +550,8 @@ async function createLazyPagesContext(options) {
385
550
  const result = {
386
551
  added: { pages: [], layouts: [], middlewares: [] },
387
552
  removed: { pages: [], layouts: [], middlewares: [] },
553
+ addedLoadings: [],
554
+ removedLoadings: [],
388
555
  staleByCascade: [],
389
556
  clientRebuilt: false,
390
557
  version: manifest.version,
@@ -406,13 +573,20 @@ async function createLazyPagesContext(options) {
406
573
  const addedMiddlewares = nextMiddlewares.filter((m) => !currentMwDirs.has(m.dirPath));
407
574
  const removedMiddlewares = [...currentMwDirs].filter((d) => !nextMwDirs.has(d));
408
575
 
576
+ const currentLoadingDirs = new Set(manifest.loadings.keys());
577
+ const nextLoadingDirs = new Set(nextLoadings.map((l) => l.dirPath));
578
+ const addedLoadings = nextLoadings.filter((l) => !currentLoadingDirs.has(l.dirPath));
579
+ const removedLoadings = [...currentLoadingDirs].filter((d) => !nextLoadingDirs.has(d));
580
+
409
581
  const noOp =
410
582
  addedPages.length === 0 &&
411
583
  removedPages.length === 0 &&
412
584
  addedLayouts.length === 0 &&
413
585
  removedLayouts.length === 0 &&
414
586
  addedMiddlewares.length === 0 &&
415
- removedMiddlewares.length === 0;
587
+ removedMiddlewares.length === 0 &&
588
+ addedLoadings.length === 0 &&
589
+ removedLoadings.length === 0;
416
590
  if (noOp) return result;
417
591
 
418
592
  // ── Apply layout add/remove ──────────────────────────────────────
@@ -445,6 +619,17 @@ async function createLazyPagesContext(options) {
445
619
  result.removed.middlewares.push(dirPath);
446
620
  }
447
621
 
622
+ for (const loading of addedLoadings) {
623
+ manifest.loadings.set(loading.dirPath, {
624
+ srcPath: path.resolve(loading.filePath),
625
+ });
626
+ result.addedLoadings.push(loading.dirPath);
627
+ }
628
+ for (const dirPath of removedLoadings) {
629
+ manifest.loadings.delete(dirPath);
630
+ result.removedLoadings.push(dirPath);
631
+ }
632
+
448
633
  // ── Apply page add/remove ────────────────────────────────────────
449
634
  const addedPagePatterns = new Set();
450
635
  for (const page of addedPages) {
@@ -494,8 +679,10 @@ async function createLazyPagesContext(options) {
494
679
  result.added.pages.length > 0 ||
495
680
  result.removed.pages.length > 0 ||
496
681
  result.added.layouts.length > 0 ||
497
- result.removed.layouts.length > 0;
498
- if (needClientRebuild) {
682
+ result.removed.layouts.length > 0 ||
683
+ result.addedLoadings.length > 0 ||
684
+ result.removedLoadings.length > 0;
685
+ if (needClientRebuild && !viteDev) {
499
686
  if (clientCtx) {
500
687
  try {
501
688
  await clientCtx.dispose();
@@ -515,22 +702,14 @@ async function createLazyPagesContext(options) {
515
702
  devMode,
516
703
  );
517
704
  const clientResult = await clientCtx.rebuild();
518
- for (const entry of manifest.entries) {
519
- const clientBundle = clientResult.bundles.get(entry.pattern);
520
- const navBundle = clientResult.navBundles.get(entry.pattern);
521
- if (clientBundle) entry.clientBundle = clientBundle;
522
- if (navBundle) entry.navBundle = navBundle;
523
- entry.layoutClientBundles = entry.layoutDirs
524
- .map((d) => clientResult.layoutNavBundles.get(d))
525
- .filter((v) => v !== undefined);
526
- entry.loadingClientBundles = entry.loadingDirs
527
- .map((d) => clientResult.loadingNavBundles.get(d))
528
- .filter((v) => v !== undefined);
529
- entry.sharedChunks = clientResult.entryChunks?.get(entry.pattern) ?? [];
530
- entry.sharedCssChunks = clientResult.entryCssChunks?.get(entry.pattern) ?? [];
531
- }
705
+ applyClientResult(clientResult);
532
706
  result.clientRebuilt = true;
533
707
  }
708
+ if (viteDev) {
709
+ const nextStylesPath = await discoverStyles(pagesDir);
710
+ manifest.stylesPath = nextStylesPath ? path.resolve(nextStylesPath) : null;
711
+ await syncViteHydrationEntries({ manifest, outDir });
712
+ }
534
713
 
535
714
  // ── Version bump + event emission ────────────────────────────────
536
715
  bumpVersion();
@@ -553,6 +732,12 @@ async function createLazyPagesContext(options) {
553
732
  for (const dirPath of result.removed.middlewares) {
554
733
  emit('update', { type: 'remove-middleware', dirPath, version: manifest.version });
555
734
  }
735
+ for (const dirPath of result.addedLoadings) {
736
+ emit('update', { type: 'add-loading', dirPath, version: manifest.version });
737
+ }
738
+ for (const dirPath of result.removedLoadings) {
739
+ emit('update', { type: 'remove-loading', dirPath, version: manifest.version });
740
+ }
556
741
  if (result.clientRebuilt) {
557
742
  emit('update', { type: 'client-rebuilt', version: manifest.version });
558
743
  }
@@ -603,9 +788,11 @@ async function createLazyPagesContext(options) {
603
788
  stale: m.stale,
604
789
  ...(m.lastBuiltAt ? { lastBuiltAt: m.lastBuiltAt } : {}),
605
790
  })),
791
+ loadings: Array.from(manifest.loadings.keys()).map((dirPath) => ({ dirPath })),
606
792
  ...(manifest.errorBundle ? { errorBundle: manifest.errorBundle } : {}),
607
793
  ...(manifest.notFoundBundle ? { notFoundBundle: manifest.notFoundBundle } : {}),
608
794
  ...(manifest.cssBundle ? { cssBundle: manifest.cssBundle } : {}),
795
+ ...(manifest.stylesPath ? { stylesPath: manifest.stylesPath } : {}),
609
796
  };
610
797
  }
611
798
 
@@ -627,12 +814,13 @@ async function createLazyPagesContext(options) {
627
814
  ensureLayoutBuilt,
628
815
  ensureMiddlewareBuilt,
629
816
  invalidate,
817
+ handleSourceChange,
630
818
  rediscover,
631
819
  dispose,
632
820
  on,
633
821
  getManifestJson,
634
822
  get clientMetafile() {
635
- return startup.clientMetafile;
823
+ return currentClientMetafile ?? startup.clientMetafile;
636
824
  },
637
825
  };
638
826
  }
@@ -0,0 +1,11 @@
1
+ import path from 'node:path';
2
+
3
+ function resolvePagesOutDir(config, rootDir, mode = 'production') {
4
+ const pages = config?.pages ?? {};
5
+ const isDev = mode === 'development';
6
+ const prodOutDir = pages.outDir ?? path.resolve(rootDir, '.build/pages');
7
+ const devOutDir = pages.devOutDir ?? path.resolve(rootDir, '.build-dev/pages');
8
+ return isDev ? devOutDir : prodOutDir;
9
+ }
10
+
11
+ export { resolvePagesOutDir };
@@ -1,6 +1,7 @@
1
1
  import { createPagesHandler } from './handler.js';
2
2
  import { createLazyPagesContext } from './lazy-context.js';
3
3
  import { createPagesWatcher } from './watcher.js';
4
+ import { resolvePagesOutDir } from './out-dir.js';
4
5
 
5
6
  class PagesRouter {
6
7
  config;
@@ -24,6 +25,8 @@ class PagesRouter {
24
25
  async init() {
25
26
  const { config, rootDir, log, mode, fileWatcher } = this;
26
27
  const isDev = mode === 'development';
28
+ const viteDev = isDev && config.pages?.vite?.enabled === true;
29
+ const outDir = resolvePagesOutDir(config, rootDir, mode);
27
30
 
28
31
  if (isDev) {
29
32
  // Dev mode: `createLazyPagesContext()` builds only the shared bits
@@ -35,9 +38,11 @@ class PagesRouter {
35
38
  this.lazyContext = await createLazyPagesContext({
36
39
  rootDir,
37
40
  pagesDir: config.pages.dir,
41
+ outDir,
38
42
  fonts: config.pages?.fonts,
39
43
  minify: false,
40
44
  devMode: true,
45
+ viteDev,
41
46
  });
42
47
  } catch (err) {
43
48
  log.error('Pages lazy context init failed', { error: String(err) });
@@ -46,9 +51,11 @@ class PagesRouter {
46
51
 
47
52
  this.handler = createPagesHandler({
48
53
  rootDir,
54
+ outDir,
49
55
  session: config.session,
50
56
  appContext: this.appContext,
51
57
  mode,
58
+ viteDev,
52
59
  ...(this.lazyContext ? { lazyContext: this.lazyContext } : {}),
53
60
  });
54
61
 
@@ -70,12 +70,14 @@ function wrapWithProviders(createElement, element, pathname, params) {
70
70
  }
71
71
  function buildCssLinkTag(manifest) {
72
72
  if (!manifest.cssBundle) return '';
73
- return `<link rel="stylesheet" href="/static/${manifest.cssBundle}" />`;
73
+ return `<link rel="stylesheet" data-arcway-css="global" href="/static/${manifest.cssBundle}" />`;
74
74
  }
75
75
  function buildRouteCssLinkTags(route) {
76
76
  const chunks = route?.sharedCssChunks ?? [];
77
77
  if (chunks.length === 0) return '';
78
- return chunks.map((c) => `<link rel="stylesheet" href="/static/${c}" />`).join('\n');
78
+ return chunks
79
+ .map((c) => `<link rel="stylesheet" data-arcway-css="route" href="/static/${c}" />`)
80
+ .join('\n');
79
81
  }
80
82
  function buildFontPreloadTags(manifest) {
81
83
  return manifest.fontPreloadHtml ?? '';
@@ -97,6 +99,19 @@ function buildScriptTags(route) {
97
99
  tags.push(`<script type="module" src="/static/${route.clientBundle}"></script>`);
98
100
  return tags.join('\n');
99
101
  }
102
+ function buildViteScriptTags(route) {
103
+ return [
104
+ `<script type="module">
105
+ import RefreshRuntime from "/@react-refresh";
106
+ RefreshRuntime.injectIntoGlobalHook(window);
107
+ window.$RefreshReg$ = () => {};
108
+ window.$RefreshSig$ = () => (type) => type;
109
+ window.__vite_plugin_react_preamble_installed__ = true;
110
+ </script>`,
111
+ `<script type="module" src="/@vite/client"></script>`,
112
+ `<script type="module" src="${route.clientBundle}"></script>`,
113
+ ].join('\n');
114
+ }
100
115
  function buildHtmlShell({ headHtml, fontPreloadTags, cssLinkTag, bodysuffix }) {
101
116
  return {
102
117
  head: `<!DOCTYPE html>
@@ -128,6 +143,7 @@ async function renderPage(
128
143
  cacheVersion,
129
144
  react,
130
145
  devMode,
146
+ viteDev = false,
131
147
  ) {
132
148
  const { createElement, renderToPipeableStream } = react;
133
149
  const bundlePath = path.join(outDir, route.serverBundle);
@@ -155,14 +171,14 @@ async function renderPage(
155
171
  layoutComponents.push(Layout);
156
172
  }
157
173
  }
158
- const scriptTags = buildScriptTags(route);
159
- const manifestCssTag = buildCssLinkTag(manifest);
160
- const routeCssTags = buildRouteCssLinkTags(route);
174
+ const scriptTags = viteDev ? buildViteScriptTags(route) : buildScriptTags(route);
175
+ const manifestCssTag = viteDev ? '' : buildCssLinkTag(manifest);
176
+ const routeCssTags = viteDev ? '' : buildRouteCssLinkTags(route);
161
177
  const cssLinkTag = [manifestCssTag, routeCssTags].filter(Boolean).join('\n');
162
178
  const fontPreloadTags = buildFontPreloadTags(manifest);
163
179
  const envScriptTag = buildEnvScriptTag(collectPublicEnv());
164
- const hmrTag = devMode ? buildHmrScript() : '';
165
- const liveReloadTag = devMode && !hmrTag ? buildLiveReloadScript() : '';
180
+ const hmrTag = devMode && !viteDev ? buildHmrScript() : '';
181
+ const liveReloadTag = devMode && !viteDev && !hmrTag ? buildLiveReloadScript() : '';
166
182
  const propsJson = JSON.stringify(params).replace(/</g, '\\u003c');
167
183
  const headData = { meta: [], links: [] };
168
184
  setSSRHeadData(headData);