@zenithbuild/cli 0.6.17 → 0.7.1
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/build/compiler-runtime.d.ts +59 -0
- package/dist/build/compiler-runtime.js +277 -0
- package/dist/build/expression-rewrites.d.ts +88 -0
- package/dist/build/expression-rewrites.js +372 -0
- package/dist/build/hoisted-code-transforms.d.ts +44 -0
- package/dist/build/hoisted-code-transforms.js +316 -0
- package/dist/build/merge-component-ir.d.ts +16 -0
- package/dist/build/merge-component-ir.js +257 -0
- package/dist/build/page-component-loop.d.ts +92 -0
- package/dist/build/page-component-loop.js +257 -0
- package/dist/build/page-ir-normalization.d.ts +23 -0
- package/dist/build/page-ir-normalization.js +370 -0
- package/dist/build/page-loop-metrics.d.ts +100 -0
- package/dist/build/page-loop-metrics.js +131 -0
- package/dist/build/page-loop-state.d.ts +261 -0
- package/dist/build/page-loop-state.js +92 -0
- package/dist/build/page-loop.d.ts +33 -0
- package/dist/build/page-loop.js +217 -0
- package/dist/build/scoped-identifier-rewrite.d.ts +112 -0
- package/dist/build/scoped-identifier-rewrite.js +245 -0
- package/dist/build/server-script.d.ts +41 -0
- package/dist/build/server-script.js +210 -0
- package/dist/build/type-declarations.d.ts +16 -0
- package/dist/build/type-declarations.js +158 -0
- package/dist/build/typescript-expression-utils.d.ts +23 -0
- package/dist/build/typescript-expression-utils.js +272 -0
- package/dist/build.d.ts +10 -18
- package/dist/build.js +74 -2261
- package/dist/component-instance-ir.d.ts +2 -2
- package/dist/component-instance-ir.js +146 -39
- package/dist/component-occurrences.js +63 -15
- package/dist/config.d.ts +66 -0
- package/dist/config.js +86 -0
- package/dist/debug-script.d.ts +1 -0
- package/dist/debug-script.js +8 -0
- package/dist/dev-build-session.d.ts +23 -0
- package/dist/dev-build-session.js +421 -0
- package/dist/dev-server.js +256 -54
- package/dist/framework-components/Image.zen +316 -0
- package/dist/images/materialize.d.ts +17 -0
- package/dist/images/materialize.js +200 -0
- package/dist/images/payload.d.ts +18 -0
- package/dist/images/payload.js +65 -0
- package/dist/images/runtime.d.ts +4 -0
- package/dist/images/runtime.js +254 -0
- package/dist/images/service.d.ts +4 -0
- package/dist/images/service.js +302 -0
- package/dist/images/shared.d.ts +58 -0
- package/dist/images/shared.js +306 -0
- package/dist/index.js +2 -17
- package/dist/manifest.js +45 -0
- package/dist/preview.d.ts +4 -1
- package/dist/preview.js +59 -6
- package/dist/resolve-components.js +20 -3
- package/dist/server-contract.js +3 -2
- package/dist/server-script-composition.d.ts +39 -0
- package/dist/server-script-composition.js +133 -0
- package/dist/startup-profile.d.ts +10 -0
- package/dist/startup-profile.js +62 -0
- package/dist/toolchain-paths.d.ts +1 -0
- package/dist/toolchain-paths.js +31 -0
- package/dist/version-check.d.ts +2 -1
- package/dist/version-check.js +12 -5
- package/package.json +5 -4
package/dist/dev-server.js
CHANGED
|
@@ -13,11 +13,16 @@
|
|
|
13
13
|
import { createServer } from 'node:http';
|
|
14
14
|
import { existsSync, watch } from 'node:fs';
|
|
15
15
|
import { readFile, stat } from 'node:fs/promises';
|
|
16
|
+
import { performance } from 'node:perf_hooks';
|
|
16
17
|
import { basename, dirname, extname, isAbsolute, join, relative, resolve } from 'node:path';
|
|
17
|
-
import {
|
|
18
|
+
import { createDevBuildSession } from './dev-build-session.js';
|
|
19
|
+
import { createStartupProfiler } from './startup-profile.js';
|
|
18
20
|
import { createSilentLogger } from './ui/logger.js';
|
|
19
21
|
import { readChangeFingerprint } from './dev-watch.js';
|
|
20
|
-
import { executeServerRoute, injectSsrPayload, loadRouteManifest, resolveWithinDist, toStaticFilePath } from './preview.js';
|
|
22
|
+
import { defaultRouteDenyMessage, executeServerRoute, injectSsrPayload, loadRouteManifest, resolveWithinDist, toStaticFilePath } from './preview.js';
|
|
23
|
+
import { materializeImageMarkup } from './images/materialize.js';
|
|
24
|
+
import { injectImageRuntimePayload } from './images/payload.js';
|
|
25
|
+
import { handleImageRequest } from './images/service.js';
|
|
21
26
|
import { resolveRequestRoute } from './server/resolve-request-route.js';
|
|
22
27
|
const MIME_TYPES = {
|
|
23
28
|
'.html': 'text/html',
|
|
@@ -25,8 +30,12 @@ const MIME_TYPES = {
|
|
|
25
30
|
'.css': 'text/css',
|
|
26
31
|
'.json': 'application/json',
|
|
27
32
|
'.png': 'image/png',
|
|
33
|
+
'.jpeg': 'image/jpeg',
|
|
28
34
|
'.jpg': 'image/jpeg',
|
|
29
|
-
'.svg': 'image/svg+xml'
|
|
35
|
+
'.svg': 'image/svg+xml',
|
|
36
|
+
'.webp': 'image/webp',
|
|
37
|
+
'.avif': 'image/avif',
|
|
38
|
+
'.gif': 'image/gif'
|
|
30
39
|
};
|
|
31
40
|
// Note: V0 HMR script injection has been moved to the runtime client.
|
|
32
41
|
// This server purely hosts the V1 HMR contract endpoints.
|
|
@@ -37,8 +46,10 @@ const MIME_TYPES = {
|
|
|
37
46
|
* @returns {Promise<{ server: import('http').Server, port: number, close: () => void }>}
|
|
38
47
|
*/
|
|
39
48
|
export async function createDevServer(options) {
|
|
49
|
+
const startupProfile = createStartupProfiler('cli-dev-server');
|
|
40
50
|
const { pagesDir, outDir, port = 3000, host = '127.0.0.1', config = {}, logger: providedLogger = null } = options;
|
|
41
51
|
const logger = providedLogger || createSilentLogger();
|
|
52
|
+
const buildSession = createDevBuildSession({ pagesDir, outDir, config, logger });
|
|
42
53
|
const resolvedPagesDir = resolve(pagesDir);
|
|
43
54
|
const resolvedOutDir = resolve(outDir);
|
|
44
55
|
const resolvedOutDirTmp = resolve(dirname(resolvedOutDir), `${basename(resolvedOutDir)}.tmp`);
|
|
@@ -63,10 +74,11 @@ export async function createDevServer(options) {
|
|
|
63
74
|
}, 15000);
|
|
64
75
|
let buildId = 0;
|
|
65
76
|
let pendingBuildId = 0;
|
|
66
|
-
let buildStatus = '
|
|
77
|
+
let buildStatus = 'building'; // 'ok' | 'error' | 'building'
|
|
67
78
|
let lastBuildMs = Date.now();
|
|
68
79
|
let durationMs = 0;
|
|
69
80
|
let buildError = null;
|
|
81
|
+
let initialBuildSettled = false;
|
|
70
82
|
const traceEnabled = config.devTrace === true || process.env.ZENITH_DEV_TRACE === '1';
|
|
71
83
|
const verboseLogging = traceEnabled || logger.mode?.logLevel === 'verbose';
|
|
72
84
|
// Stable dev CSS endpoint points to this backing asset.
|
|
@@ -74,6 +86,9 @@ export async function createDevServer(options) {
|
|
|
74
86
|
let currentCssHref = '';
|
|
75
87
|
let currentCssContent = '';
|
|
76
88
|
let actualPort = port;
|
|
89
|
+
let currentRoutes = [];
|
|
90
|
+
const rebuildDebounceMs = 5;
|
|
91
|
+
const queuedRebuildDebounceMs = 5;
|
|
77
92
|
function _publicHost() {
|
|
78
93
|
if (host === '0.0.0.0' || host === '::') {
|
|
79
94
|
return '127.0.0.1';
|
|
@@ -164,6 +179,34 @@ export async function createDevServer(options) {
|
|
|
164
179
|
}
|
|
165
180
|
return secFetchDest === 'empty';
|
|
166
181
|
}
|
|
182
|
+
function _isBuildSwapReadError(error) {
|
|
183
|
+
const code = typeof error?.code === 'string' ? error.code : '';
|
|
184
|
+
return code === 'ENOENT' || code === 'ENOTDIR';
|
|
185
|
+
}
|
|
186
|
+
function _delay(ms) {
|
|
187
|
+
return new Promise((resolveDelay) => {
|
|
188
|
+
setTimeout(resolveDelay, ms);
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
async function _readFileForRequest(filePath, encoding = undefined) {
|
|
192
|
+
const attempts = buildStatus === 'building' ? 200 : 1;
|
|
193
|
+
let lastError = null;
|
|
194
|
+
for (let attempt = 0; attempt < attempts; attempt += 1) {
|
|
195
|
+
try {
|
|
196
|
+
return encoding === undefined
|
|
197
|
+
? await readFile(filePath)
|
|
198
|
+
: await readFile(filePath, encoding);
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
lastError = error;
|
|
202
|
+
if (!_isBuildSwapReadError(error) || attempt === attempts - 1) {
|
|
203
|
+
throw error;
|
|
204
|
+
}
|
|
205
|
+
await _delay(50);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
throw lastError;
|
|
209
|
+
}
|
|
167
210
|
function _buildNotFoundPayload(pathname, category, cause) {
|
|
168
211
|
const payload = {
|
|
169
212
|
kind: 'zenith_dev_not_found',
|
|
@@ -231,6 +274,10 @@ export async function createDevServer(options) {
|
|
|
231
274
|
if (cssAssets.length === 0) {
|
|
232
275
|
return '';
|
|
233
276
|
}
|
|
277
|
+
const devStable = cssAssets.find((entry) => entry.endsWith('/styles.dev.css'));
|
|
278
|
+
if (devStable) {
|
|
279
|
+
return devStable;
|
|
280
|
+
}
|
|
234
281
|
const preferred = cssAssets.find((entry) => /\/styles(\.|\/|$)/.test(entry));
|
|
235
282
|
return preferred || cssAssets[0];
|
|
236
283
|
}
|
|
@@ -307,6 +354,24 @@ export async function createDevServer(options) {
|
|
|
307
354
|
currentCssContent = cssContent;
|
|
308
355
|
return true;
|
|
309
356
|
}
|
|
357
|
+
async function _loadRoutesForRequests() {
|
|
358
|
+
if (buildStatus === 'building' && Array.isArray(currentRoutes) && currentRoutes.length > 0) {
|
|
359
|
+
return currentRoutes;
|
|
360
|
+
}
|
|
361
|
+
try {
|
|
362
|
+
const routes = await loadRouteManifest(outDir);
|
|
363
|
+
if (Array.isArray(routes) && routes.length > 0) {
|
|
364
|
+
currentRoutes = routes;
|
|
365
|
+
return routes;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
catch (error) {
|
|
369
|
+
if (!(Array.isArray(currentRoutes) && currentRoutes.length > 0)) {
|
|
370
|
+
throw error;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
return currentRoutes;
|
|
374
|
+
}
|
|
310
375
|
function _broadcastEvent(type, payload = {}) {
|
|
311
376
|
const eventBuildId = Number.isInteger(payload.buildId) ? payload.buildId : buildId;
|
|
312
377
|
const data = JSON.stringify({
|
|
@@ -329,22 +394,62 @@ export async function createDevServer(options) {
|
|
|
329
394
|
}
|
|
330
395
|
}
|
|
331
396
|
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
logger.
|
|
397
|
+
async function _runInitialBuild() {
|
|
398
|
+
buildStatus = 'building';
|
|
399
|
+
buildError = null;
|
|
400
|
+
const startTime = Date.now();
|
|
401
|
+
startupProfile.emit('initial_build_start', { buildId });
|
|
402
|
+
try {
|
|
403
|
+
logger.build('Initial build (id=0)', { onceKey: 'dev-initial-build' });
|
|
404
|
+
const initialBuild = await buildSession.build();
|
|
405
|
+
const cssReady = await _syncCssStateFromBuild(initialBuild, buildId);
|
|
406
|
+
currentRoutes = await loadRouteManifest(outDir);
|
|
407
|
+
buildStatus = 'ok';
|
|
408
|
+
buildError = null;
|
|
409
|
+
lastBuildMs = Date.now();
|
|
410
|
+
durationMs = lastBuildMs - startTime;
|
|
411
|
+
if (cssReady && currentCssHref.length > 0) {
|
|
412
|
+
logger.css(`ready (${currentCssHref})`, { onceKey: `css-ready:${buildId}:${currentCssHref}` });
|
|
413
|
+
}
|
|
414
|
+
_trace('state_snapshot', {
|
|
415
|
+
status: buildStatus,
|
|
416
|
+
buildId,
|
|
417
|
+
cssHref: currentCssHref,
|
|
418
|
+
durationMs
|
|
419
|
+
});
|
|
420
|
+
startupProfile.emit('initial_build_complete', {
|
|
421
|
+
buildId,
|
|
422
|
+
status: buildStatus,
|
|
423
|
+
durationMs,
|
|
424
|
+
cssReady,
|
|
425
|
+
routes: Array.isArray(currentRoutes) ? currentRoutes.length : 0
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
catch (err) {
|
|
429
|
+
buildStatus = 'error';
|
|
430
|
+
buildError = { message: err instanceof Error ? err.message : String(err) };
|
|
431
|
+
lastBuildMs = Date.now();
|
|
432
|
+
durationMs = lastBuildMs - startTime;
|
|
433
|
+
logger.error('initial build failed', {
|
|
434
|
+
hint: 'fix the error and restart dev',
|
|
435
|
+
error: err
|
|
436
|
+
});
|
|
437
|
+
_trace('state_snapshot', {
|
|
438
|
+
status: buildStatus,
|
|
439
|
+
buildId,
|
|
440
|
+
durationMs,
|
|
441
|
+
error: buildError
|
|
442
|
+
});
|
|
443
|
+
startupProfile.emit('initial_build_complete', {
|
|
444
|
+
buildId,
|
|
445
|
+
status: buildStatus,
|
|
446
|
+
durationMs,
|
|
447
|
+
error: buildError?.message || ''
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
finally {
|
|
451
|
+
initialBuildSettled = true;
|
|
339
452
|
}
|
|
340
|
-
}
|
|
341
|
-
catch (err) {
|
|
342
|
-
buildStatus = 'error';
|
|
343
|
-
buildError = { message: err instanceof Error ? err.message : String(err) };
|
|
344
|
-
logger.error('initial build failed', {
|
|
345
|
-
hint: 'fix the error and restart dev',
|
|
346
|
-
error: err
|
|
347
|
-
});
|
|
348
453
|
}
|
|
349
454
|
const server = createServer(async (req, res) => {
|
|
350
455
|
const requestBase = typeof req.headers.host === 'string' && req.headers.host.length > 0
|
|
@@ -460,8 +565,24 @@ export async function createDevServer(options) {
|
|
|
460
565
|
res.end(currentCssContent);
|
|
461
566
|
return;
|
|
462
567
|
}
|
|
568
|
+
if (pathname === '/_zenith/image') {
|
|
569
|
+
await handleImageRequest(req, res, {
|
|
570
|
+
requestUrl: url,
|
|
571
|
+
projectRoot,
|
|
572
|
+
config: config.images
|
|
573
|
+
});
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
463
576
|
if (pathname === '/__zenith/route-check') {
|
|
464
577
|
try {
|
|
578
|
+
if (!initialBuildSettled && buildStatus === 'building') {
|
|
579
|
+
res.writeHead(503, { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' });
|
|
580
|
+
res.end(JSON.stringify({
|
|
581
|
+
error: 'initial_build_pending',
|
|
582
|
+
message: 'initial build still in progress'
|
|
583
|
+
}));
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
465
586
|
// Security: Require explicitly designated header to prevent public oracle probing
|
|
466
587
|
if (req.headers['x-zenith-route-check'] !== '1') {
|
|
467
588
|
res.writeHead(403, { 'Content-Type': 'application/json' });
|
|
@@ -481,7 +602,7 @@ export async function createDevServer(options) {
|
|
|
481
602
|
res.end(JSON.stringify({ error: 'external_route_evaluation_forbidden' }));
|
|
482
603
|
return;
|
|
483
604
|
}
|
|
484
|
-
const routes = await
|
|
605
|
+
const routes = await _loadRoutesForRequests();
|
|
485
606
|
const resolvedCheck = resolveRequestRoute(targetUrl, routes);
|
|
486
607
|
if (!resolvedCheck.matched || !resolvedCheck.route) {
|
|
487
608
|
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
@@ -538,18 +659,48 @@ export async function createDevServer(options) {
|
|
|
538
659
|
let resolvedPathFor404 = null;
|
|
539
660
|
let staticRootFor404 = null;
|
|
540
661
|
try {
|
|
662
|
+
if (!initialBuildSettled && buildStatus === 'building') {
|
|
663
|
+
const pendingPayload = {
|
|
664
|
+
kind: 'zenith_dev_build_pending',
|
|
665
|
+
requestedPath: pathname,
|
|
666
|
+
buildId,
|
|
667
|
+
buildStatus,
|
|
668
|
+
hint: 'Initial build is still running. Retry shortly or inspect /__zenith_dev/state.'
|
|
669
|
+
};
|
|
670
|
+
if (_looksLikeJsonRequest(req, pathname)) {
|
|
671
|
+
res.writeHead(503, {
|
|
672
|
+
'Content-Type': 'application/json',
|
|
673
|
+
'Cache-Control': 'no-store'
|
|
674
|
+
});
|
|
675
|
+
res.end(JSON.stringify(pendingPayload));
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
res.writeHead(503, {
|
|
679
|
+
'Content-Type': 'text/html; charset=utf-8',
|
|
680
|
+
'Cache-Control': 'no-store'
|
|
681
|
+
});
|
|
682
|
+
res.end([
|
|
683
|
+
'<!DOCTYPE html>',
|
|
684
|
+
'<html><head><meta charset="utf-8"><title>Zenith Dev Building</title></head>',
|
|
685
|
+
'<body style="font-family: ui-monospace, SFMono-Regular, Menlo, monospace; padding: 20px; background: #101216; color: #e6edf3;">',
|
|
686
|
+
'<h1 style="margin-top:0;">Zenith Dev Building</h1>',
|
|
687
|
+
`<pre style="white-space: pre-wrap; line-height: 1.5;">Requested: ${pathname}\nStatus: initial build running\nHint: ${pendingPayload.hint}</pre>`,
|
|
688
|
+
'</body></html>'
|
|
689
|
+
].join(''));
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
541
692
|
const requestExt = extname(pathname);
|
|
542
693
|
if (requestExt && requestExt !== '.html') {
|
|
543
694
|
const assetPath = join(outDir, pathname);
|
|
544
695
|
resolvedPathFor404 = assetPath;
|
|
545
696
|
staticRootFor404 = outDir;
|
|
546
|
-
const asset = await
|
|
697
|
+
const asset = await _readFileForRequest(assetPath);
|
|
547
698
|
const mime = MIME_TYPES[requestExt] || 'application/octet-stream';
|
|
548
699
|
res.writeHead(200, { 'Content-Type': mime });
|
|
549
700
|
res.end(asset);
|
|
550
701
|
return;
|
|
551
702
|
}
|
|
552
|
-
const routes = await
|
|
703
|
+
const routes = await _loadRoutesForRequests();
|
|
553
704
|
const resolved = resolveRequestRoute(url, routes);
|
|
554
705
|
let filePath = null;
|
|
555
706
|
if (resolved.matched && resolved.route) {
|
|
@@ -611,17 +762,28 @@ export async function createDevServer(options) {
|
|
|
611
762
|
if (result && result.kind === 'deny') {
|
|
612
763
|
const status = Number.isInteger(result.status) ? result.status : 403;
|
|
613
764
|
res.writeHead(status, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
614
|
-
res.end(result.message || (status
|
|
765
|
+
res.end(result.message || defaultRouteDenyMessage(status));
|
|
615
766
|
return;
|
|
616
767
|
}
|
|
617
768
|
if (result && result.kind === 'data' && result.data && typeof result.data === 'object' && !Array.isArray(result.data)) {
|
|
618
769
|
ssrPayload = result.data;
|
|
619
770
|
}
|
|
620
771
|
}
|
|
621
|
-
let content = await
|
|
772
|
+
let content = await _readFileForRequest(filePath, 'utf8');
|
|
773
|
+
if (resolved.matched && resolved.route?.page_asset) {
|
|
774
|
+
const pageAssetPath = resolveWithinDist(outDir, resolved.route.page_asset);
|
|
775
|
+
content = await materializeImageMarkup({
|
|
776
|
+
html: content,
|
|
777
|
+
pageAssetPath,
|
|
778
|
+
payload: buildSession.getImageRuntimePayload(),
|
|
779
|
+
ssrData: ssrPayload,
|
|
780
|
+
routePathname: resolved.route.path || pathname
|
|
781
|
+
});
|
|
782
|
+
}
|
|
622
783
|
if (ssrPayload) {
|
|
623
784
|
content = injectSsrPayload(content, ssrPayload);
|
|
624
785
|
}
|
|
786
|
+
content = injectImageRuntimePayload(content, buildSession.getImageRuntimePayload());
|
|
625
787
|
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
626
788
|
res.end(content);
|
|
627
789
|
}
|
|
@@ -711,7 +873,8 @@ export async function createDevServer(options) {
|
|
|
711
873
|
* Start watching source roots for changes.
|
|
712
874
|
*/
|
|
713
875
|
function _startWatcher() {
|
|
714
|
-
const
|
|
876
|
+
const watcherStartedAt = performance.now();
|
|
877
|
+
const triggerBuildDrain = (delayMs = rebuildDebounceMs) => {
|
|
715
878
|
if (_buildDebounce !== null) {
|
|
716
879
|
clearTimeout(_buildDebounce);
|
|
717
880
|
}
|
|
@@ -724,7 +887,8 @@ export async function createDevServer(options) {
|
|
|
724
887
|
if (_buildInFlight) {
|
|
725
888
|
return;
|
|
726
889
|
}
|
|
727
|
-
const
|
|
890
|
+
const changedFiles = Array.from(_queuedFiles);
|
|
891
|
+
const changed = changedFiles.map(_toDisplayPath).sort();
|
|
728
892
|
if (changed.length === 0) {
|
|
729
893
|
return;
|
|
730
894
|
}
|
|
@@ -738,9 +902,13 @@ export async function createDevServer(options) {
|
|
|
738
902
|
const startTime = Date.now();
|
|
739
903
|
const previousCssAssetPath = currentCssAssetPath;
|
|
740
904
|
const previousCssContent = currentCssContent;
|
|
905
|
+
const onlyCss = changed.length > 0 && changed.every((f) => f.endsWith('.css'));
|
|
741
906
|
try {
|
|
742
|
-
const buildResult = await build({
|
|
907
|
+
const buildResult = await buildSession.build({ changedFiles, logger });
|
|
743
908
|
const cssReady = await _syncCssStateFromBuild(buildResult, cycleBuildId);
|
|
909
|
+
if (!onlyCss) {
|
|
910
|
+
currentRoutes = await loadRouteManifest(outDir);
|
|
911
|
+
}
|
|
744
912
|
const cssChanged = cssReady && (currentCssAssetPath !== previousCssAssetPath ||
|
|
745
913
|
currentCssContent !== previousCssContent);
|
|
746
914
|
buildId = cycleBuildId;
|
|
@@ -768,7 +936,6 @@ export async function createDevServer(options) {
|
|
|
768
936
|
logger.hmr(`css_update (buildId=${cycleBuildId})`);
|
|
769
937
|
_broadcastEvent('css_update', { href: currentCssHref, changedFiles: changed });
|
|
770
938
|
}
|
|
771
|
-
const onlyCss = changed.length > 0 && changed.every((f) => f.endsWith('.css'));
|
|
772
939
|
if (!onlyCss) {
|
|
773
940
|
logger.hmr(`reload (buildId=${cycleBuildId})`);
|
|
774
941
|
_broadcastEvent('reload', { changedFiles: changed });
|
|
@@ -804,7 +971,7 @@ export async function createDevServer(options) {
|
|
|
804
971
|
finally {
|
|
805
972
|
_buildInFlight = false;
|
|
806
973
|
if (_queuedFiles.size > 0) {
|
|
807
|
-
triggerBuildDrain(
|
|
974
|
+
triggerBuildDrain(queuedRebuildDebounceMs);
|
|
808
975
|
}
|
|
809
976
|
}
|
|
810
977
|
};
|
|
@@ -837,35 +1004,70 @@ export async function createDevServer(options) {
|
|
|
837
1004
|
// fs.watch recursive may not be supported on this platform/root
|
|
838
1005
|
}
|
|
839
1006
|
}
|
|
1007
|
+
startupProfile.emit('watcher_ready', {
|
|
1008
|
+
roots: roots.length,
|
|
1009
|
+
activeWatchers: _watchers.length,
|
|
1010
|
+
durationMs: startupProfile.roundMs(performance.now() - watcherStartedAt)
|
|
1011
|
+
});
|
|
840
1012
|
}
|
|
841
|
-
|
|
842
|
-
|
|
1013
|
+
const closeServer = () => {
|
|
1014
|
+
clearInterval(sseHeartbeat);
|
|
1015
|
+
for (const watcher of _watchers) {
|
|
1016
|
+
try {
|
|
1017
|
+
watcher.close();
|
|
1018
|
+
}
|
|
1019
|
+
catch {
|
|
1020
|
+
// ignore close errors
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
_watchers = [];
|
|
1024
|
+
for (const client of hmrClients) {
|
|
1025
|
+
try {
|
|
1026
|
+
client.end();
|
|
1027
|
+
}
|
|
1028
|
+
catch { }
|
|
1029
|
+
}
|
|
1030
|
+
hmrClients.length = 0;
|
|
1031
|
+
server.close();
|
|
1032
|
+
};
|
|
1033
|
+
return new Promise((resolve, reject) => {
|
|
1034
|
+
let settled = false;
|
|
1035
|
+
server.once('error', (error) => {
|
|
1036
|
+
if (!settled) {
|
|
1037
|
+
settled = true;
|
|
1038
|
+
reject(error);
|
|
1039
|
+
}
|
|
1040
|
+
});
|
|
1041
|
+
server.listen(port, host, async () => {
|
|
843
1042
|
actualPort = server.address().port;
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
server,
|
|
1043
|
+
startupProfile.emit('server_bound', {
|
|
1044
|
+
host: _publicHost(),
|
|
847
1045
|
port: actualPort,
|
|
848
|
-
|
|
849
|
-
clearInterval(sseHeartbeat);
|
|
850
|
-
for (const watcher of _watchers) {
|
|
851
|
-
try {
|
|
852
|
-
watcher.close();
|
|
853
|
-
}
|
|
854
|
-
catch {
|
|
855
|
-
// ignore close errors
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
_watchers = [];
|
|
859
|
-
for (const client of hmrClients) {
|
|
860
|
-
try {
|
|
861
|
-
client.end();
|
|
862
|
-
}
|
|
863
|
-
catch { }
|
|
864
|
-
}
|
|
865
|
-
hmrClients.length = 0;
|
|
866
|
-
server.close();
|
|
867
|
-
}
|
|
1046
|
+
buildStatus
|
|
868
1047
|
});
|
|
1048
|
+
_trace('server_bound', {
|
|
1049
|
+
host: _publicHost(),
|
|
1050
|
+
port: actualPort,
|
|
1051
|
+
buildStatus
|
|
1052
|
+
});
|
|
1053
|
+
try {
|
|
1054
|
+
await _runInitialBuild();
|
|
1055
|
+
_startWatcher();
|
|
1056
|
+
if (!settled) {
|
|
1057
|
+
settled = true;
|
|
1058
|
+
resolve({
|
|
1059
|
+
server,
|
|
1060
|
+
port: actualPort,
|
|
1061
|
+
close: closeServer
|
|
1062
|
+
});
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
catch (error) {
|
|
1066
|
+
if (!settled) {
|
|
1067
|
+
settled = true;
|
|
1068
|
+
reject(error);
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
869
1071
|
});
|
|
870
1072
|
});
|
|
871
1073
|
}
|