Skip to content

Alternative HMR versioning#1076

Open
alexzherdev wants to merge 6 commits intomainfrom
azherdev/hmr-timestamps
Open

Alternative HMR versioning#1076
alexzherdev wants to merge 6 commits intomainfrom
azherdev/hmr-timestamps

Conversation

@alexzherdev
Copy link
Copy Markdown
Collaborator

@alexzherdev alexzherdev commented Mar 31, 2026

Motivation

Timestamp-based cache busting is linked to Chrome devtools crashing in Confluence due to the accumulation of duplicate copies of source code parsed out of sourcemaps.

Changes

Codex generated description:

Introduced a new hmrBundleVersioning feature flag to gate the HMR cache-busting behavior change.

When the flag is enabled, the browser HMR runtime now bumps a shared global bundle version once per handled HMR update and reuses that version for all refreshed asset URLs in that cycle. That shared token is used for CSS link replacement, hot-update script loading, and worker-side HMR imports. When the flag is disabled, those paths fall back to the previous Date.now()-based cache-busting behavior.

The JS runtime was updated to follow the same flag. Runtime-generated asset URLs, such as new URL(..., import.meta.url) references under HMR, now use the shared bundle version only when hmrBundleVersioning is enabled; otherwise they keep appending a fresh timestamp as before. This keeps the HMR runtime and JS runtime aligned behind one switch.

I also updated the HMR integration coverage to explicitly enable the new flag in the URL and CSS refresh scenarios, and added a regression case that checks multiple URL references in a single HMR cycle receive the same version token, while a later cycle gets a new one.

Checklist

  • Existing or new tests cover this change
  • There is a changeset for this change, or one is not required
  • Added documentation for any new features to the docs/ folder

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 31, 2026

🦋 Changeset detected

Latest commit: e8266dc

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 112 packages
Name Type
@atlaspack/feature-flags Patch
@atlaspack/runtime-browser-hmr Patch
@atlaspack/runtime-js Patch
@atlaspack/core Patch
@atlaspack/bundler-default Patch
atlaspack Patch
@atlaspack/build-cache Patch
@atlaspack/cache Patch
@atlaspack/cli Patch
@atlaspack/fs Patch
@atlaspack/graph Patch
@atlaspack/types-internal Patch
@atlaspack/utils Patch
@atlaspack/inspector Patch
@atlaspack/optimizer-inline-requires Patch
@atlaspack/packager-html Patch
@atlaspack/packager-js Patch
@atlaspack/reporter-cli Patch
@atlaspack/reporter-compiled-css-in-js-migration-map Patch
@atlaspack/reporter-conditional-manifest Patch
@atlaspack/runtime-react-refresh Patch
@atlaspack/transformer-compiled-css-in-js Patch
@atlaspack/transformer-css Patch
@atlaspack/transformer-html Patch
@atlaspack/transformer-js Patch
@atlaspack/transformer-react-refresh-wrap Patch
@atlaspack/transformer-tokens Patch
@atlaspack/node-resolver-core Patch
@atlaspack/config-default Patch
@atlaspack/config-webextension Patch
@atlaspack/e2e-tests Patch
@atlaspack/register Patch
@atlaspack/test-utils Patch
@atlaspack/bundle-stats Patch
@atlaspack/packaging-test-harness Patch
@atlaspack/query Patch
@atlaspack/optimizer-image Patch
@atlaspack/reporter-bundle-stats Patch
@atlaspack/transformer-image Patch
@atlaspack/inspector-frontend Patch
@atlaspack/package-manager Patch
@atlaspack/workers Patch
@atlaspack/link Patch
@atlaspack/codeframe Patch
@atlaspack/logger Patch
@atlaspack/plugin Patch
@atlaspack/profiler Patch
@atlaspack/types Patch
@atlaspack/packager-css Patch
@atlaspack/reporter-bundle-buddy Patch
@atlaspack/transformer-less Patch
@atlaspack/transformer-postcss Patch
@atlaspack/transformer-xml Patch
@atlaspack/ts-utils Patch
@atlaspack/optimizer-blob-url Patch
@atlaspack/optimizer-css Patch
@atlaspack/optimizer-data-url Patch
@atlaspack/optimizer-svgo Patch
@atlaspack/optimizer-swc Patch
@atlaspack/optimizer-terser Patch
@atlaspack/packager-raw-url Patch
@atlaspack/packager-svg Patch
@atlaspack/packager-webextension Patch
@atlaspack/packager-xml Patch
@atlaspack/reporter-build-metrics Patch
@atlaspack/reporter-bundle-analyzer Patch
@atlaspack/reporter-dev-server Patch
@atlaspack/reporter-json Patch
@atlaspack/reporter-lsp Patch
@atlaspack/reporter-sourcemap-visualiser Patch
@atlaspack/reporter-tracer Patch
@atlaspack/resolver-glob Patch
@atlaspack/runtime-service-worker Patch
@atlaspack/runtime-webextension Patch
@atlaspack/transformer-babel Patch
@atlaspack/transformer-compiled Patch
@atlaspack/transformer-posthtml Patch
@atlaspack/transformer-typescript-types Patch
@atlaspack/transformer-webextension Patch
@atlaspack/transformer-webmanifest Patch
@atlaspack/watcher-watchman-js Patch
@atlaspack/validator-eslint Patch
@atlaspack/validator-typescript Patch
@atlaspack/resolver-default Patch
@atlaspack/resolver-tesseract Patch
@atlaspack/bundler-library Patch
@atlaspack/compressor-brotli Patch
@atlaspack/compressor-gzip Patch
@atlaspack/compressor-raw Patch
@atlaspack/namer-default Patch
@atlaspack/optimizer-cssnano Patch
@atlaspack/optimizer-htmlnano Patch
@atlaspack/packager-raw Patch
@atlaspack/packager-ts Patch
@atlaspack/packager-wasm Patch
@atlaspack/transformer-compiled-external Patch
@atlaspack/transformer-glsl Patch
@atlaspack/transformer-graphql Patch
@atlaspack/transformer-inline-string Patch
@atlaspack/transformer-inline Patch
@atlaspack/transformer-json Patch
@atlaspack/transformer-jsonld Patch
@atlaspack/transformer-mdx Patch
@atlaspack/transformer-pug Patch
@atlaspack/transformer-raw Patch
@atlaspack/transformer-sass Patch
@atlaspack/transformer-svg-react Patch
@atlaspack/transformer-svg Patch
@atlaspack/transformer-toml Patch
@atlaspack/transformer-typescript-tsc Patch
@atlaspack/transformer-worklet Patch
@atlaspack/transformer-yaml Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

if (typeof document !== 'undefined') {
let script = document.createElement('script');
script.src = asset.url + '?t=' + Date.now();
script.src = appendBundleVersion(asset.url);

Check failure

Code scanning / CodeQL

Client-side cross-site scripting High

Cross-site scripting vulnerability due to
user-provided value
.

Copilot Autofix

AI 7 days ago

To fix this, we should prevent arbitrary, attacker-controlled URLs from being used as script.src. The safest general approach is to validate or normalize asset.url before using it, restricting it to expected forms (for example, only same-origin URLs, or only relative paths under a known base) and rejecting or ignoring anything else. This keeps the existing HMR behavior for valid bundle URLs while blocking injection of external or JavaScript pseudo-URLs.

The best minimal fix in this snippet is to introduce a small helper that “sanitizes” or validates URLs coming from HMR assets, and then use that helper wherever we load scripts via asset.url (in document.createElement('script') and in the worker import/importScripts paths). Specifically, inside hmr-runtime.ts we can add a sanitizeAssetUrl function near appendBundleVersion that (1) rejects dangerous URL schemes like javascript: and data:, and (2) ensures the URL is either relative or same-origin (e.g., by constructing a URL object with location.origin as base and checking the origin). If the URL fails validation, the function can throw or cause the download to reject, preventing script execution. Then we update the uses at lines 476, 497, and 506 to call sanitizeAssetUrl(asset.url) before passing it to appendBundleVersion. No external dependencies are needed; we can use the built-in URL class and location/self.location where available.

Concretely:

  • In packages/runtimes/hmr/src/loaders/hmr-runtime.ts, above appendBundleVersion, define function sanitizeAssetUrl(rawUrl: string): string { ... } that:
    • Trims whitespace.
    • If typeof location !== 'undefined', builds new URL(rawUrl, location.href) and:
      • Rejects if url.protocol is not http: or https:.
      • Optionally rejects if url.origin !== location.origin (to enforce same-origin).
      • Returns url.href (a normalized absolute URL).
    • If location is not available (e.g., worker context), falls back to a conservative check that disallows javascript: and data: prefixes and returns the original string.
  • Change:
    • script.src = appendBundleVersion(asset.url);
      to
      script.src = appendBundleVersion(sanitizeAssetUrl(asset.url));
    • __parcel__import__(appendBundleVersion(asset.url))
      to use sanitizeAssetUrl(asset.url) similarly.
    • __parcel__importScripts__(appendBundleVersion(asset.url))
      likewise.

This keeps all existing functionality for valid HMR asset URLs but ensures that untrusted or cross-origin URLs cannot silently be executed.


Suggested changeset 1
packages/runtimes/hmr/src/loaders/hmr-runtime.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/packages/runtimes/hmr/src/loaders/hmr-runtime.ts b/packages/runtimes/hmr/src/loaders/hmr-runtime.ts
--- a/packages/runtimes/hmr/src/loaders/hmr-runtime.ts
+++ b/packages/runtimes/hmr/src/loaders/hmr-runtime.ts
@@ -117,6 +117,38 @@
   return nextVersion;
 }
 
+function sanitizeAssetUrl(rawUrl: string): string {
+  if (typeof rawUrl !== 'string') {
+    throw new Error('Invalid asset URL');
+  }
+  const url = rawUrl.trim();
+
+  // Disallow obvious dangerous schemes even if URL/Location are unavailable.
+  const lower = url.toLowerCase();
+  if (lower.startsWith('javascript:') || lower.startsWith('data:')) {
+    throw new Error('Blocked unsafe asset URL scheme');
+  }
+
+  // In browser contexts, normalize and restrict to same-origin HTTP(S) URLs.
+  if (typeof location !== 'undefined') {
+    try {
+      const parsed = new URL(url, location.href);
+      if (
+        (parsed.protocol === 'http:' || parsed.protocol === 'https:') &&
+        parsed.origin === location.origin
+      ) {
+        return parsed.href;
+      }
+      throw new Error('Blocked cross-origin or non-HTTP(S) asset URL');
+    } catch {
+      throw new Error('Blocked invalid asset URL');
+    }
+  }
+
+  // Fallback for non-window contexts (e.g. some workers): rely on scheme check above.
+  return url;
+}
+
 function appendBundleVersion(url: string) {
   // @ts-expect-error TS2304
   if (!HMR_ENABLE_BUNDLE_VERSION) {
@@ -473,7 +505,7 @@
   if (asset.type === 'js') {
     if (typeof document !== 'undefined') {
       let script = document.createElement('script');
-      script.src = appendBundleVersion(asset.url);
+      script.src = appendBundleVersion(sanitizeAssetUrl(asset.url));
       if (asset.outputFormat === 'esmodule') {
         script.type = 'module';
       }
@@ -494,7 +526,9 @@
       // Worker scripts
       if (asset.outputFormat === 'esmodule') {
         // @ts-expect-error TS2304
-        return __parcel__import__(appendBundleVersion(asset.url));
+        return __parcel__import__(
+          appendBundleVersion(sanitizeAssetUrl(asset.url)),
+        );
       } else {
         return new Promise(
           (
@@ -503,7 +537,9 @@
           ) => {
             try {
               // @ts-expect-error TS2304
-              __parcel__importScripts__(appendBundleVersion(asset.url));
+              __parcel__importScripts__(
+                appendBundleVersion(sanitizeAssetUrl(asset.url)),
+              );
               // @ts-expect-error TS2794
               resolve();
             } catch (err: any) {
EOF
Copilot is powered by AI and may make mistakes. Always verify output.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't look like a legit issue to me.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mattcompiles do you reckon we can dismiss this? I think this is the only failing CodeQL check.

if (typeof document !== 'undefined') {
let script = document.createElement('script');
script.src = asset.url + '?t=' + Date.now();
script.src = appendBundleVersion(asset.url);

Check warning

Code scanning / CodeQL

Client-side URL redirect Medium

Untrusted URL redirection depends on a
user-provided value
.

Copilot Autofix

AI 7 days ago

In general, to fix untrusted URL usage in client-side redirects or script loads, you restrict navigation or loading to either (1) same-origin paths or (2) a small, explicit allowlist of trusted origins/paths. You avoid using fully user-controlled URLs directly in window.location, script.src, img.src, or similar sinks without validation.

For this specific case, we should ensure that asset.url cannot cause navigation or loading from an untrusted origin. The least invasive change, without altering overall HMR behavior, is to make appendBundleVersion normalize the URL so that only relative URLs (or same-origin URLs) are allowed, and to prevent protocol-relative or absolute cross-origin URLs. We only touch the shown file. The best approach here is:

  1. Add a small helper to sanitize/normalize the asset URL.

    • Reject javascript: and other dangerous schemes.
    • If the URL is absolute and same-origin, allow it.
    • If it is relative (starts with / or no scheme), resolve it against location.origin when window/location are available.
    • If we cannot safely resolve or check, conservatively return the input unchanged (to minimize functional impact where no browser context is present, e.g. workers), but we keep the main protection for the document case where script.src is used.
  2. Modify appendBundleVersion(url: string) so it first passes url through this sanitizer before appending the version query parameter. This way:

    • The browser case (document.createElement('script') on line 475–490) will use a sanitized URL.
    • Worker cases still go through appendBundleVersion and thus benefit where possible.

Concretely:

  • In packages/runtimes/hmr/src/loaders/hmr-runtime.ts, above appendBundleVersion, define sanitizeBundleUrl (or similarly named) that:

    • Returns the original url early if typeof window === 'undefined' or typeof location === 'undefined', to avoid changing non-browser contexts.
    • Trims whitespace.
    • URL-decodes via decodeURI for comparison (defensively in try/catch).
    • Rejects / blocks URLs that start with javascript:, data:, or other non-http(s) schemes.
    • For absolute URLs (new URL(url, location.href)), ensures parsed.origin === location.origin; otherwise, returns a safe fallback (e.g. location.origin + pathname) or just location.origin depending on what we can preserve safely. To avoid altering functionality too much, we keep the path if same-origin, but if cross-origin we instead return location.origin + the original pathname or a default known-safe path (here, we can just strip origin and keep pathname if possible).
    • For relative URLs, returns the relative form unchanged (but normalized).
  • Inside appendBundleVersion(url: string), call const safeUrl = sanitizeBundleUrl(url); and then perform all further logic using safeUrl instead of the original url.

This keeps existing behavior for the normal, expected asset URLs (relative or same-origin), and prevents script loads from attacker-controlled cross-origin or dangerous-scheme URLs when the HMR server is compromised.


Suggested changeset 1
packages/runtimes/hmr/src/loaders/hmr-runtime.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/packages/runtimes/hmr/src/loaders/hmr-runtime.ts b/packages/runtimes/hmr/src/loaders/hmr-runtime.ts
--- a/packages/runtimes/hmr/src/loaders/hmr-runtime.ts
+++ b/packages/runtimes/hmr/src/loaders/hmr-runtime.ts
@@ -117,18 +117,60 @@
   return nextVersion;
 }
 
+function sanitizeBundleUrl(url: string): string {
+  // Only enforce strict checks in a browser-like environment where we control script.src.
+  if (typeof window === 'undefined' || typeof location === 'undefined') {
+    return url;
+  }
+
+  let trimmed = url.trim();
+  // Basic scheme protection: disallow dangerous schemes like javascript: or data:
+  let lower = trimmed.toLowerCase();
+  if (
+    lower.startsWith('javascript:') ||
+    lower.startsWith('data:') ||
+    lower.startsWith('vbscript:')
+  ) {
+    // Block entirely by returning a safe no-op relative URL.
+    return '/';
+  }
+
+  try {
+    // Resolve against current location to inspect origin.
+    let resolved = new URL(trimmed, location.href);
+
+    // If the original specifies a different origin explicitly, do not allow it.
+    if (resolved.origin !== location.origin) {
+      // Strip the foreign origin but keep the path if present.
+      return resolved.pathname + resolved.search + resolved.hash;
+    }
+
+    // Same-origin URLs are allowed as-is (normalized form).
+    return resolved.pathname + resolved.search + resolved.hash;
+  } catch {
+    // If URL construction fails, fall back to the original string.
+    return trimmed;
+  }
+}
+
 function appendBundleVersion(url: string) {
+  const safeUrl = sanitizeBundleUrl(url);
   // @ts-expect-error TS2304
   if (!HMR_ENABLE_BUNDLE_VERSION) {
-    return url + (url.includes('?') ? '&' : '?') + 't=' + Date.now();
+    return (
+      safeUrl +
+      (safeUrl.includes('?') ? '&' : '?') +
+      't=' +
+      Date.now()
+    );
   }
 
   let version = getBundleVersion();
   if (version == null) {
-    return url;
+    return safeUrl;
   }
 
-  return url + (url.includes('?') ? '&' : '?') + 't=' + version;
+  return safeUrl + (safeUrl.includes('?') ? '&' : '?') + 't=' + version;
 }
 
 function getHostname() {
EOF
@@ -117,18 +117,60 @@
return nextVersion;
}

function sanitizeBundleUrl(url: string): string {
// Only enforce strict checks in a browser-like environment where we control script.src.
if (typeof window === 'undefined' || typeof location === 'undefined') {
return url;
}

let trimmed = url.trim();
// Basic scheme protection: disallow dangerous schemes like javascript: or data:
let lower = trimmed.toLowerCase();
if (
lower.startsWith('javascript:') ||
lower.startsWith('data:') ||
lower.startsWith('vbscript:')
) {
// Block entirely by returning a safe no-op relative URL.
return '/';
}

try {
// Resolve against current location to inspect origin.
let resolved = new URL(trimmed, location.href);

// If the original specifies a different origin explicitly, do not allow it.
if (resolved.origin !== location.origin) {
// Strip the foreign origin but keep the path if present.
return resolved.pathname + resolved.search + resolved.hash;
}

// Same-origin URLs are allowed as-is (normalized form).
return resolved.pathname + resolved.search + resolved.hash;
} catch {
// If URL construction fails, fall back to the original string.
return trimmed;
}
}

function appendBundleVersion(url: string) {
const safeUrl = sanitizeBundleUrl(url);
// @ts-expect-error TS2304
if (!HMR_ENABLE_BUNDLE_VERSION) {
return url + (url.includes('?') ? '&' : '?') + 't=' + Date.now();
return (
safeUrl +
(safeUrl.includes('?') ? '&' : '?') +
't=' +
Date.now()
);
}

let version = getBundleVersion();
if (version == null) {
return url;
return safeUrl;
}

return url + (url.includes('?') ? '&' : '?') + 't=' + version;
return safeUrl + (safeUrl.includes('?') ? '&' : '?') + 't=' + version;
}

function getHostname() {
Copilot is powered by AI and may make mistakes. Always verify output.
assetFromValue(asset, options),
]),
),
changedAssets: skipChangedAssets
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changed-assets code is making all asset URLs involved in one HMR update share a single version token, instead of each URL generating its own Date.now() query string.

Before:

  • every refreshed asset URL did its own ?t=${Date.now()}
  • that meant one HMR cycle could produce slightly different timestamps for JS, CSS, new URL(...) assets, worker imports, and so on
  • if multiple related assets were refreshed together, they weren’t guaranteed to point at the same logical update version

Now:

  • when Atlaspack receives and handles an HMR update, it bumps globalThis.__parcel__hmrBundleVersion once
  • every asset refresh during that HMR cycle appends ?t=
  • the next HMR cycle bumps it again

In hmr-runtime.ts, that shared token is used for:

  • CSS link replacement
  • JS hot-update script loads
  • worker/module import paths during HMR
  • In JSRuntime.ts, the same token is used for runtime-generated asset URLs, like new URL(...)-style bundle references.

So the practical effect is:

  • one update cycle gets one cache-busting token
  • subsequent update cycles get a new token
  • all refreshed assets stay in sync within a cycle
  • you avoid subtle mismatches caused by a bunch of independent Date.now() calls firing a few milliseconds apart

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see how changedAssets is related to the URLs though. Assets are modules or files, where-as the URLs are related to bundles. I think some systems, like incremental symbol prop will break if you just blank the changed assets param.

I don't see how changedAssets is related to this change at all. Can you try testing your change without this code and see if it still works?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks! Looks like it still works so I removed these changes.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 31, 2026

📊 Type Coverage Report

Coverage Comparison

Metric Baseline Current Change
Coverage Percentage 92.28% 92.28% ➡️ 0.00%
Correctly Typed 223,737 223,864 +127
Total Expressions 242,432 242,566 +134
Untyped Expressions 18,695 18,702 +7

Files with Most Type Issues (Top 15)

File Issues Affected Lines
packages/core/integration-tests/test/javascript.ts 1152 745
packages/core/integration-tests/test/cache.ts 884 625
packages/core/integration-tests/test/scope-hoisting.ts 624 491
packages/utils/node-resolver-core/test/resolver.ts 476 177
packages/core/integration-tests/test/html.ts 468 294
packages/core/integration-tests/test/sourcemaps.ts 364 182
packages/core/test-utils/src/utils.ts 330 205
packages/core/integration-tests/test/incremental-bundling.ts 298 206
packages/core/core/src/dumpGraphToGraphViz.ts 251 108
packages/core/integration-tests/test/transpilation.ts 239 143
packages/core/integration-tests/test/output-formats.ts 227 161
packages/transformers/webextension/src/WebExtensionTransformer.ts 210 80
packages/core/core/src/requests/AssetGraphRequestRust.ts 197 84
packages/core/core/src/requests/BundleGraphRequestRust.ts 195 68
packages/core/integration-tests/test/css-modules.ts 191 107

This report was generated by the Type Coverage GitHub Action

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 31, 2026

📊 Benchmark Results

🎉 Performance improvements detected!

📊 Benchmark Results

Overall Performance

Test Duration JS Memory Peak Native Memory Peak vs Baseline Status
Three.js Real Repository (JS) 15.26s 1.93GB 2.07GB -6.69% duration, -6.61% JS memory 🟢 Improvement
Three.js Real Repository (V3) 20.66s 3.17GB 3.50GB +3.07% duration, +1.16% JS memory 🟡 Neutral

🔍 Detailed Phase Analysis

Three.js Real Repository (JS)

Phase Duration (avg) Duration (p95) Memory Peak (avg) Memory Peak (p95)
resolving 7.24s 7.54s 1.34GB 1.59GB
transforming 7.23s 7.50s 1.35GB 1.60GB
bundling 7.04s 7.32s 1.35GB 1.61GB
bundled 6.66s 6.96s 1.42GB 1.67GB
packaging 4.46s 4.68s 1.54GB 1.79GB
optimizing 4.32s 4.53s 1.93GB 2.08GB

Three.js Real Repository (V3)

Phase Duration (avg) Duration (p95) Memory Peak (avg) Memory Peak (p95)
building 13.58s 17.90s 2.46GB 2.88GB
bundling 12.94s 17.35s 2.47GB 2.89GB
bundled 12.58s 16.99s 2.65GB 3.06GB
packaging 6.07s 6.77s 2.81GB 3.13GB
optimizing 5.87s 6.51s 3.17GB 3.50GB

💾 Unified Memory Analysis

Three.js Real Repository (JS) Memory Statistics

Memory Type Metric Min Mean Median P95 P99 Max Std Dev
JavaScript RSS 1.25GB 1.74GB 1.78GB 2.08GB 2.08GB 2.08GB 256.30MB
Heap Used 80.88MB 90.28MB 92.45MB 104.22MB 104.22MB 104.22MB 8.70MB
Heap Total 96.10MB 126.76MB 127.39MB 192.41MB 192.41MB 192.41MB 21.24MB
External 38.88MB 105.97MB 173.02MB 173.09MB 173.09MB 173.09MB 67.07MB
Native (Rust) Physical Memory 1.53GB 1.71GB 1.69GB 1.94GB 2.05GB 2.07GB 143.75MB
Virtual Memory 29.86GB 30.51GB 30.51GB 30.76GB 30.84GB 30.86GB 163.09MB

Sample Counts: JS: 14, Native: 246

Three.js Real Repository (V3) Memory Statistics

Memory Type Metric Min Mean Median P95 P99 Max Std Dev
JavaScript RSS 2.33GB 2.91GB 2.97GB 3.50GB 3.50GB 3.50GB 360.78MB
Heap Used 77.64MB 78.26MB 78.23MB 79.59MB 79.59MB 79.59MB 0.51MB
Heap Total 93.20MB 99.87MB 95.20MB 125.95MB 125.95MB 125.95MB 10.59MB
External 179.71MB 182.60MB 185.49MB 185.49MB 185.49MB 185.49MB 2.89MB
Native (Rust) Physical Memory 2.81GB 3.10GB 3.12GB 3.38GB 3.50GB 3.50GB 168.84MB
Virtual Memory 30.90GB 33.39GB 33.71GB 33.98GB 34.10GB 34.10GB 813.30MB

Sample Counts: JS: 14, Native: 239

🖥️ Environment

  • Node.js: v22.17.0
  • Platform: linux (x64)
  • CPU: AMD EPYC 7763 64-Core Processor
  • Total Memory: 15.62GB
  • Git SHA: e8266dc
  • Branch: azherdev/hmr-timestamps
  • Timestamp: 2026-04-02T22:11:24.879Z

@alexzherdev alexzherdev force-pushed the azherdev/hmr-timestamps branch 2 times, most recently from 24f411a to a0e3dec Compare April 1, 2026 03:24
@alexzherdev alexzherdev force-pushed the azherdev/hmr-timestamps branch from a0e3dec to 82438b3 Compare April 2, 2026 00:11
@alexzherdev alexzherdev force-pushed the azherdev/hmr-timestamps branch from 82438b3 to e8266dc Compare April 2, 2026 20:46
@alexzherdev alexzherdev marked this pull request as ready for review April 2, 2026 22:48
@alexzherdev alexzherdev requested a review from a team as a code owner April 2, 2026 22:48
},
);

it.v2(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason you marked this as v2?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants