@nativescript/vite 8.0.0-alpha.13 → 8.0.0-alpha.15
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/helpers/main-entry.d.ts +2 -1
- package/helpers/main-entry.js +70 -8
- package/helpers/main-entry.js.map +1 -1
- package/helpers/ns-core-url.js +23 -0
- package/helpers/ns-core-url.js.map +1 -1
- package/hmr/client/css-handler.d.ts +1 -0
- package/hmr/client/css-handler.js +33 -5
- package/hmr/client/css-handler.js.map +1 -1
- package/hmr/client/css-update-overlay.d.ts +18 -0
- package/hmr/client/css-update-overlay.js +27 -0
- package/hmr/client/css-update-overlay.js.map +1 -0
- package/hmr/client/index.js +20 -0
- package/hmr/client/index.js.map +1 -1
- package/hmr/entry-runtime.d.ts +1 -0
- package/hmr/entry-runtime.js +95 -11
- package/hmr/entry-runtime.js.map +1 -1
- package/hmr/helpers/ast-normalizer.js +45 -5
- package/hmr/helpers/ast-normalizer.js.map +1 -1
- package/hmr/server/core-sanitize.d.ts +23 -0
- package/hmr/server/core-sanitize.js +60 -0
- package/hmr/server/core-sanitize.js.map +1 -1
- package/hmr/server/vite-plugin.js +24 -4
- package/hmr/server/vite-plugin.js.map +1 -1
- package/hmr/server/websocket-core-bridge.d.ts +10 -0
- package/hmr/server/websocket-core-bridge.js +35 -5
- package/hmr/server/websocket-core-bridge.js.map +1 -1
- package/hmr/server/websocket-css-hot-update.d.ts +33 -0
- package/hmr/server/websocket-css-hot-update.js +65 -0
- package/hmr/server/websocket-css-hot-update.js.map +1 -0
- package/hmr/server/websocket-ns-m-finalize.js +2 -4
- package/hmr/server/websocket-ns-m-finalize.js.map +1 -1
- package/hmr/server/websocket-served-module-helpers.js +19 -6
- package/hmr/server/websocket-served-module-helpers.js.map +1 -1
- package/hmr/server/websocket.d.ts +1 -0
- package/hmr/server/websocket.js +120 -67
- package/hmr/server/websocket.js.map +1 -1
- package/hmr/shared/runtime/boot-placeholder-ui.d.ts +69 -0
- package/hmr/shared/runtime/boot-placeholder-ui.js +101 -0
- package/hmr/shared/runtime/boot-placeholder-ui.js.map +1 -0
- package/hmr/shared/runtime/boot-progress.d.ts +40 -0
- package/hmr/shared/runtime/boot-progress.js +128 -0
- package/hmr/shared/runtime/boot-progress.js.map +1 -0
- package/hmr/shared/runtime/boot-timeline.d.ts +1 -0
- package/hmr/shared/runtime/boot-timeline.js +1 -0
- package/hmr/shared/runtime/boot-timeline.js.map +1 -1
- package/hmr/shared/runtime/dev-overlay.js +96 -5
- package/hmr/shared/runtime/dev-overlay.js.map +1 -1
- package/hmr/shared/runtime/root-placeholder.js +317 -47
- package/hmr/shared/runtime/root-placeholder.js.map +1 -1
- package/hmr/shared/runtime/session-bootstrap.js +132 -18
- package/hmr/shared/runtime/session-bootstrap.js.map +1 -1
- package/hmr/shared/vendor/manifest.js +18 -2
- package/hmr/shared/vendor/manifest.js.map +1 -1
- package/package.json +1 -1
package/hmr/server/websocket.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createRequire } from 'node:module';
|
|
2
|
-
import {
|
|
2
|
+
import { sanitizeStrayCoreReferences, isDeepCoreSubpath, rewriteSpecifiersForDevice } from './core-sanitize.js';
|
|
3
3
|
import { buildDefaultExportFooter, buildShapeInstallHeader, hasNamespaceReExport, rewriteNamespaceReExportsForShape } from './ns-core-cjs-shape.js';
|
|
4
4
|
// AST tooling for robust transformations
|
|
5
5
|
import { parse as babelParse } from '@babel/parser';
|
|
@@ -33,10 +33,11 @@ import { astExtractImportsAndStripTypes } from '../helpers/ast-extract.js';
|
|
|
33
33
|
import { getProjectAppPath, getProjectAppRelativePath, getProjectAppVirtualPath } from '../../helpers/utils.js';
|
|
34
34
|
import { buildRuntimeConfig, generateImportMap } from './import-map.js';
|
|
35
35
|
import { getCliFlags } from '../../helpers/cli-flags.js';
|
|
36
|
-
import { normalizeCoreSub as normalizeCoreSubCanonical } from '../../helpers/ns-core-url.js';
|
|
36
|
+
import { buildCoreUrl, buildCoreUrlPath, normalizeCoreSub as normalizeCoreSubCanonical } from '../../helpers/ns-core-url.js';
|
|
37
37
|
import { isRuntimeGraphExcludedPath, matchesRuntimeGraphModuleId, normalizeRuntimeGraphPath, shouldIncludeRuntimeGraphFile, shouldSkipRuntimeGraphDirectoryName } from './runtime-graph-filter.js';
|
|
38
38
|
import { resolveAngularCoreHmrImportSource, rewriteAngularEntryRegisterOnly } from './websocket-angular-entry.js';
|
|
39
39
|
import { angularSourceHasSemanticDecorator, canonicalizeTransformRequestCacheKey, collectAngularEvictionUrls, collectAngularHotUpdateRoots, collectAngularTransformCacheInvalidationUrls, collectAngularTransitiveImportersForInvalidation, collectGraphUpdateModulesForHotUpdate, normalizeHotReloadMatchPath, shouldInvalidateAngularTransitiveImporters, shouldSuppressDefaultViteHotUpdate, shouldSuppressViteFullReloadPayload } from './websocket-angular-hot-update.js';
|
|
40
|
+
import { collectCssHotUpdatePaths } from './websocket-css-hot-update.js';
|
|
40
41
|
import { classifyGraphUpsert, shouldBroadcastGraphUpsertDelta, shouldBumpGraphVersion } from './websocket-graph-upsert.js';
|
|
41
42
|
import { classifyBootRoute, classifyHmrUpdateKind, createColdBootRequestCounter, formatHmrUpdateSummary, formatPopulateInitialGraphSummary, formatServerStartupBanner } from './perf-instrumentation.js';
|
|
42
43
|
import { createHmrPendingMessage } from './websocket-hmr-pending.js';
|
|
@@ -55,6 +56,7 @@ export { rewriteAngularEntryRegisterOnly } from './websocket-angular-entry.js';
|
|
|
55
56
|
// without churn while the implementation lives in a focused module.
|
|
56
57
|
export { formatNsMHmrServeTag, rewriteNsMImportPathForHmr } from './websocket-ns-m-paths.js';
|
|
57
58
|
export { angularSourceHasSemanticDecorator, canonicalizeTransformRequestCacheKey, collectAngularEvictionUrls, collectAngularHotUpdateRoots, collectAngularTransformCacheInvalidationUrls, collectAngularTransitiveImportersForInvalidation, collectGraphUpdateModulesForHotUpdate, createSharedTransformRequestRunner, normalizeHotReloadMatchPath, shouldInvalidateAngularTransitiveImporters, shouldSuppressDefaultViteHotUpdate, shouldSuppressViteFullReloadPayload, classifyGraphUpsert, shouldBroadcastGraphUpsertDelta, shouldBumpGraphVersion };
|
|
59
|
+
export { collectCssHotUpdatePaths } from './websocket-css-hot-update.js';
|
|
58
60
|
const pluginTransformTypescript = (() => {
|
|
59
61
|
const requireFromHere = createRequire(import.meta.url);
|
|
60
62
|
const loaded = requireFromHere('@babel/plugin-transform-typescript');
|
|
@@ -215,14 +217,13 @@ function hoistTopLevelStaticImports(code) {
|
|
|
215
217
|
}
|
|
216
218
|
return `${hoisted.join('\n')}\n${stripped.replace(/^\s*\n+/, '')}`;
|
|
217
219
|
}
|
|
220
|
+
// Duplicate of `websocket-served-module-helpers.ts::buildBootProgressSnippet`
|
|
221
|
+
// — both copies must stay in lock-step. See the canonical doc there for
|
|
222
|
+
// why the snippet must remain fully synchronous (top-level await on a
|
|
223
|
+
// boot-tagged module trips the iOS 10 s async-module deadline).
|
|
218
224
|
export function buildBootProgressSnippet(bootModuleLabel) {
|
|
219
225
|
const normalizedLabel = JSON.stringify(String(bootModuleLabel || '').replace(/\\/g, '/'));
|
|
220
|
-
return [
|
|
221
|
-
`const __nsBootGlobal=globalThis;`,
|
|
222
|
-
`try{if(!__nsBootGlobal.__NS_HMR_BOOT_COMPLETE__){const __nsBootApi=__nsBootGlobal.__NS_HMR_DEV_OVERLAY__;if(__nsBootApi&&typeof __nsBootApi.setBootStage==='function'){const __nsBootCount=(__nsBootGlobal.__NS_HMR_BOOT_MODULE_COUNT__=Number(__nsBootGlobal.__NS_HMR_BOOT_MODULE_COUNT__||0)+1);__nsBootGlobal.__NS_HMR_BOOT_LAST_MODULE__=${normalizedLabel};const __nsBootNow=Date.now();const __nsBootLast=Number(__nsBootGlobal.__NS_HMR_BOOT_LAST_PROGRESS_AT__||0);if(__nsBootCount<=8||__nsBootCount%6===0||__nsBootNow-__nsBootLast>90){__nsBootGlobal.__NS_HMR_BOOT_LAST_PROGRESS_AT__=__nsBootNow;const __nsBootProgress=Math.min(94,82+Math.min(10,Math.round((Math.log(__nsBootCount+1)/Math.LN2)*2)));__nsBootApi.setBootStage('importing-main',{detail:'Evaluated '+__nsBootCount+' modules\\n'+__nsBootGlobal.__NS_HMR_BOOT_LAST_MODULE__,attempt:Number(__nsBootGlobal.__NS_HMR_BOOT_MAIN_ATTEMPT__||1),attempts:Number(__nsBootGlobal.__NS_HMR_BOOT_MAIN_ATTEMPTS__||6),progress:__nsBootProgress});}}}}catch(__nsBootErr){}`,
|
|
223
|
-
`if(!__nsBootGlobal.__NS_HMR_BOOT_COMPLETE__){const __nsBootCount=Number(__nsBootGlobal.__NS_HMR_BOOT_MODULE_COUNT__||0);if(__nsBootCount<=24||__nsBootCount%8===0){await new Promise((resolve)=>setTimeout(resolve,0));}}`,
|
|
224
|
-
'',
|
|
225
|
-
].join('\n');
|
|
226
|
+
return [`const __nsBootGlobal=globalThis;`, `try{if(!__nsBootGlobal.__NS_HMR_BOOT_COMPLETE__){__nsBootGlobal.__NS_HMR_BOOT_MODULE_COUNT__=Number(__nsBootGlobal.__NS_HMR_BOOT_MODULE_COUNT__||0)+1;__nsBootGlobal.__NS_HMR_BOOT_LAST_MODULE__=${normalizedLabel};}}catch(__nsBootErr){}`, ''].join('\n');
|
|
226
227
|
}
|
|
227
228
|
function rewriteVitePrebundleImportsForDevice(code, preserveVendorImports) {
|
|
228
229
|
const imports = collectTopLevelImportRecords(code);
|
|
@@ -1171,7 +1172,20 @@ function processCodeForDevice(code, isVitePreBundled, preserveVendorImports = fa
|
|
|
1171
1172
|
// Minimal process shim — populated with CLI --env.* flags at module load time.
|
|
1172
1173
|
// In production builds, Vite/Rollup replaces process.env.* statically.
|
|
1173
1174
|
// In HMR dev mode the code runs as-is on device, so we need the shim.
|
|
1174
|
-
|
|
1175
|
+
//
|
|
1176
|
+
// IMPORTANT: every check goes through `globalThis.process` (a member
|
|
1177
|
+
// expression), NEVER bare `typeof process` (an identifier reference).
|
|
1178
|
+
// bare identifier resolution
|
|
1179
|
+
// against runtime-added global object properties is not reliable in
|
|
1180
|
+
// V8 module scope. `globalThis.process` is unambiguous: it always
|
|
1181
|
+
// reads the `process` property off the (single) global object.
|
|
1182
|
+
//
|
|
1183
|
+
// The shim is also strictly additive — it only initializes
|
|
1184
|
+
// `globalThis.process` and `globalThis.process.env` if they are
|
|
1185
|
+
// missing. App code that pre-populates `process.env` (e.g. an Azure
|
|
1186
|
+
// App Configuration boot module) is preserved; we never overwrite a
|
|
1187
|
+
// populated env with the bare `{ NODE_ENV: 'development' }` stub.
|
|
1188
|
+
`if (typeof globalThis.process === "undefined" || globalThis.process === null) { globalThis.process = { env: ${__processEnvJson} }; } else if (!globalThis.process.env) { globalThis.process.env = ${__processEnvJson}; }`,
|
|
1175
1189
|
'const __ANDROID__ = globalThis.__ANDROID__ !== undefined ? globalThis.__ANDROID__ : false;',
|
|
1176
1190
|
'const __IOS__ = globalThis.__IOS__ !== undefined ? globalThis.__IOS__ : false;',
|
|
1177
1191
|
'const __VISIONOS__ = globalThis.__VISIONOS__ !== undefined ? globalThis.__VISIONOS__ : false;',
|
|
@@ -1423,21 +1437,11 @@ function processCodeForDevice(code, isVitePreBundled, preserveVendorImports = fa
|
|
|
1423
1437
|
}
|
|
1424
1438
|
}
|
|
1425
1439
|
catch { }
|
|
1426
|
-
//
|
|
1427
|
-
//
|
|
1428
|
-
//
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
}
|
|
1432
|
-
catch { }
|
|
1433
|
-
try {
|
|
1434
|
-
result = fixDanglingCoreFrom(result);
|
|
1435
|
-
}
|
|
1436
|
-
catch { }
|
|
1437
|
-
try {
|
|
1438
|
-
result = normalizeAnyCoreSpecToBridge(result);
|
|
1439
|
-
}
|
|
1440
|
-
catch { }
|
|
1440
|
+
// Apply the three-pass safety net for stray @nativescript/core references
|
|
1441
|
+
// (naked string literals, dangling `from` merges, lingering resolved-path
|
|
1442
|
+
// references). Centralised in core-sanitize.sanitizeStrayCoreReferences so
|
|
1443
|
+
// every NS-M emitter applies the same passes in the same order.
|
|
1444
|
+
result = sanitizeStrayCoreReferences(result);
|
|
1441
1445
|
result = ensureVariableDynamicImportHelper(result);
|
|
1442
1446
|
// Normalize any lingering @nativescript/core imports to the /ns/core bridge (non-destructive best-effort)
|
|
1443
1447
|
try {
|
|
@@ -1869,10 +1873,30 @@ export function rewriteImports(code, importerPath, sfcFileMap, depFileMap, proje
|
|
|
1869
1873
|
try {
|
|
1870
1874
|
let coreAliasIdx = 0;
|
|
1871
1875
|
const mkAlias = () => `__NSC${coreAliasIdx++}`;
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
+
// Use the canonical PATH form `/ns/core/<sub>` (NOT the legacy
|
|
1877
|
+
// `/ns/core?p=<sub>` query form). The iOS HTTP ESM loader caches
|
|
1878
|
+
// module records by URL string — if vendor.mjs's external imports
|
|
1879
|
+
// resolve to `/ns/core/<sub>` (via the import map + buildCoreUrl()
|
|
1880
|
+
// canonical generator) and the app's rewritten imports resolve to
|
|
1881
|
+
// `/ns/core?p=<sub>`, V8 creates two distinct module records for
|
|
1882
|
+
// the same logical core subpath. Each gets its own class
|
|
1883
|
+
// identities (TextBase, View, etc.), and side-effect patches
|
|
1884
|
+
// applied to one (e.g. @nativescript-community/text's
|
|
1885
|
+
// `TextBase.prototype.setTextDecorationAndTransform` override
|
|
1886
|
+
// installed when vendor.mjs evaluates `overrideSpanAndFormattedString()`
|
|
1887
|
+
// from `@nativescript-community/ui-label/index-common.js`) are
|
|
1888
|
+
// invisible to the other — manifesting as inconsistent line-height /
|
|
1889
|
+
// letter-spacing rendering between HMR and no-HMR.
|
|
1890
|
+
//
|
|
1891
|
+
// Mirrors `normalizeCoreSub()` (helpers/ns-core-url.ts) so the URL
|
|
1892
|
+
// produced here is byte-identical to what `buildCoreUrl()` produces
|
|
1893
|
+
// for the bundle entry, import map, and external-urls plugin.
|
|
1894
|
+
// Delegate to the ONE canonical URL builder so every emitter (this
|
|
1895
|
+
// rewriter, core-sanitize, the runtime import map, the ns-core-external-urls
|
|
1896
|
+
// build plugin, and main-entry) produces byte-identical URLs for
|
|
1897
|
+
// the same logical core module. Any drift here would re-introduce
|
|
1898
|
+
// the realm-split bug.
|
|
1899
|
+
const coreUrl = (sub) => (httpOriginSafe ? buildCoreUrl(httpOriginSafe, sub) : buildCoreUrlPath(sub));
|
|
1876
1900
|
// Case 1: import { A, B } from '@nativescript/core[/sub]'
|
|
1877
1901
|
result = result.replace(/(^|\n)\s*import\s*\{\s*([^}]+?)\s*\}\s*from\s+["']@nativescript\/core([^"'\n]*)["'];?/g, (_m, pfx, names, sub) => {
|
|
1878
1902
|
const alias = mkAlias();
|
|
@@ -3824,16 +3848,14 @@ export const piniaSymbol = p.piniaSymbol;
|
|
|
3824
3848
|
code = ensureGuardPlainDynamicImports(code, getServerOrigin(server));
|
|
3825
3849
|
}
|
|
3826
3850
|
catch { }
|
|
3827
|
-
// Extra hardening
|
|
3828
|
-
// -
|
|
3829
|
-
//
|
|
3830
|
-
//
|
|
3831
|
-
//
|
|
3851
|
+
// Extra hardening before the fast-fail assertion: run the
|
|
3852
|
+
// consolidated stray-core-reference safety net. If any
|
|
3853
|
+
// rewrite occurred, leave a diagnostic marker so the
|
|
3854
|
+
// pipeline review log explains why the served code carries
|
|
3855
|
+
// it.
|
|
3832
3856
|
try {
|
|
3833
3857
|
const __before = code;
|
|
3834
|
-
code =
|
|
3835
|
-
code = fixDanglingCoreFrom(code);
|
|
3836
|
-
code = normalizeAnyCoreSpecToBridge(code);
|
|
3858
|
+
code = sanitizeStrayCoreReferences(code);
|
|
3837
3859
|
if (code !== __before) {
|
|
3838
3860
|
code = `// [hmr-sanitize] core-literal->bridge\n` + code;
|
|
3839
3861
|
}
|
|
@@ -4368,6 +4390,23 @@ export const piniaSymbol = p.piniaSymbol;
|
|
|
4368
4390
|
const coreRequest = parseCoreBridgeRequest(urlObj.pathname, urlObj.searchParams, Number(graphVersion || 0));
|
|
4369
4391
|
if (!coreRequest)
|
|
4370
4392
|
return next();
|
|
4393
|
+
// Non-canonical incoming URL — every emitter is supposed
|
|
4394
|
+
// to canonicalize before hitting the device. Promote the
|
|
4395
|
+
// drift to a 301 redirect so iOS still gets the file at
|
|
4396
|
+
// the canonical URL (no realm split) but the offending
|
|
4397
|
+
// caller is forced to update. We log the offending raw
|
|
4398
|
+
// pathname so the regression source is easy to find.
|
|
4399
|
+
if (coreRequest.canonicalPath) {
|
|
4400
|
+
try {
|
|
4401
|
+
console.warn(`[ns-core-bridge] 301 ${urlObj.pathname}${urlObj.search} → ${coreRequest.canonicalPath} (non-canonical core URL — please update emitter)`);
|
|
4402
|
+
}
|
|
4403
|
+
catch { }
|
|
4404
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
4405
|
+
res.setHeader('Location', coreRequest.canonicalPath);
|
|
4406
|
+
res.statusCode = 301;
|
|
4407
|
+
res.end();
|
|
4408
|
+
return;
|
|
4409
|
+
}
|
|
4371
4410
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
4372
4411
|
res.setHeader('Content-Type', 'application/javascript; charset=utf-8');
|
|
4373
4412
|
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0');
|
|
@@ -6460,6 +6499,51 @@ export const piniaSymbol = p.piniaSymbol;
|
|
|
6460
6499
|
console.warn('[hmr-ws][v2] failed graph update', e);
|
|
6461
6500
|
}
|
|
6462
6501
|
const root = server.config.root || process.cwd();
|
|
6502
|
+
// CSS hot-update — handled BEFORE the project-scope filter
|
|
6503
|
+
// because workspace `@import` deps live outside `<root>/`.
|
|
6504
|
+
// The helper maps in-scope edits to their own path and
|
|
6505
|
+
// out-of-scope edits to `app.css` (Vite re-runs PostCSS
|
|
6506
|
+
// through the `@import` chain on the next fetch).
|
|
6507
|
+
if (file.endsWith('.css')) {
|
|
6508
|
+
const cssPaths = collectCssHotUpdatePaths({
|
|
6509
|
+
file,
|
|
6510
|
+
root,
|
|
6511
|
+
appRootDir: APP_ROOT_DIR,
|
|
6512
|
+
appEntryCss: path.resolve(root, APP_ROOT_DIR, 'app.css'),
|
|
6513
|
+
});
|
|
6514
|
+
if (cssPaths.length > 0) {
|
|
6515
|
+
updateMetrics.tAfterFramework = Date.now();
|
|
6516
|
+
try {
|
|
6517
|
+
const origin = getServerOrigin(server);
|
|
6518
|
+
const timestamp = Date.now();
|
|
6519
|
+
const msg = {
|
|
6520
|
+
type: 'ns:css-updates',
|
|
6521
|
+
origin,
|
|
6522
|
+
updates: cssPaths.map((cssPath) => ({
|
|
6523
|
+
type: 'css-update',
|
|
6524
|
+
path: cssPath,
|
|
6525
|
+
acceptedPath: cssPath,
|
|
6526
|
+
timestamp,
|
|
6527
|
+
})),
|
|
6528
|
+
};
|
|
6529
|
+
wss.clients.forEach((client) => {
|
|
6530
|
+
if (isSocketClientOpen(client)) {
|
|
6531
|
+
client.send(JSON.stringify(msg));
|
|
6532
|
+
updateMetrics.recipients += 1;
|
|
6533
|
+
}
|
|
6534
|
+
});
|
|
6535
|
+
}
|
|
6536
|
+
catch (error) {
|
|
6537
|
+
console.warn('[hmr-ws] CSS update failed:', error);
|
|
6538
|
+
}
|
|
6539
|
+
if (verbose)
|
|
6540
|
+
console.log(`[hmr-ws] Hot update for: ${file} → broadcast CSS paths: ${cssPaths.join(', ')}`);
|
|
6541
|
+
emitHmrUpdateSummary();
|
|
6542
|
+
return;
|
|
6543
|
+
}
|
|
6544
|
+
// CSS without a broadcast target (no appEntryCss
|
|
6545
|
+
// configured) — fall through to the scope filter.
|
|
6546
|
+
}
|
|
6463
6547
|
const srcDir = `${root}/src`;
|
|
6464
6548
|
const coreDir = `${root}/core`;
|
|
6465
6549
|
const appDir = `${root}/${APP_ROOT_DIR}`;
|
|
@@ -6471,37 +6555,6 @@ export const piniaSymbol = p.piniaSymbol;
|
|
|
6471
6555
|
return;
|
|
6472
6556
|
if (verbose)
|
|
6473
6557
|
console.log(`[hmr-ws] Hot update for: ${file}`);
|
|
6474
|
-
// Handle CSS updates
|
|
6475
|
-
if (file.endsWith('.css')) {
|
|
6476
|
-
updateMetrics.tAfterFramework = Date.now();
|
|
6477
|
-
try {
|
|
6478
|
-
let rel = '/' + path.posix.normalize(path.relative(root, file)).split(path.sep).join('/');
|
|
6479
|
-
const origin = getServerOrigin(server);
|
|
6480
|
-
const msg = {
|
|
6481
|
-
type: 'ns:css-updates',
|
|
6482
|
-
origin,
|
|
6483
|
-
updates: [
|
|
6484
|
-
{
|
|
6485
|
-
type: 'css-update',
|
|
6486
|
-
path: rel,
|
|
6487
|
-
acceptedPath: rel,
|
|
6488
|
-
timestamp: Date.now(),
|
|
6489
|
-
},
|
|
6490
|
-
],
|
|
6491
|
-
};
|
|
6492
|
-
wss.clients.forEach((client) => {
|
|
6493
|
-
if (isSocketClientOpen(client)) {
|
|
6494
|
-
client.send(JSON.stringify(msg));
|
|
6495
|
-
updateMetrics.recipients += 1;
|
|
6496
|
-
}
|
|
6497
|
-
});
|
|
6498
|
-
}
|
|
6499
|
-
catch (error) {
|
|
6500
|
-
console.warn('[hmr-ws] CSS update failed:', error);
|
|
6501
|
-
}
|
|
6502
|
-
emitHmrUpdateSummary();
|
|
6503
|
-
return;
|
|
6504
|
-
}
|
|
6505
6558
|
// Framework-specific hot update handling
|
|
6506
6559
|
if (ACTIVE_STRATEGY.flavor === 'angular') {
|
|
6507
6560
|
// For Angular, react to component TS or external template HTML changes under /src
|