Skip to content

Commit

Permalink
fix: cache nested loops (#1677)
Browse files Browse the repository at this point in the history
  • Loading branch information
pauldambra authored Jan 22, 2025
1 parent 43e111d commit d97b413
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 19 deletions.
68 changes: 52 additions & 16 deletions patches/@[email protected]
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
diff --git a/dist/record.js b/dist/record.js
index d9c57625633fb87da27fc5948c1b15a7c4e4caa5..472c9f1359baf685279614c47426648102479efb 100644
index d9c57625633fb87da27fc5948c1b15a7c4e4caa5..ff1783439be7fdd6ad947b805324e4c7f8f70851 100644
--- a/dist/record.js
+++ b/dist/record.js
@@ -68,10 +68,10 @@ function getUntaintedPrototype$1(key) {
Expand All @@ -25,12 +25,25 @@ index d9c57625633fb87da27fc5948c1b15a7c4e4caa5..472c9f1359baf685279614c474266481
class Mirror {
constructor() {
__publicField$1(this, "idNodeMap", /* @__PURE__ */ new Map());
@@ -426,23 +429,81 @@ function absolutifyURLs(cssText, href) {
function normalizeCssString(cssText) {
return cssText.replace(/(\/\*[^*]*\*\/)|[\s;]/g, "");
@@ -423,26 +426,96 @@ function absolutifyURLs(cssText, href) {
}
);
}
+// these operations can be slow, let's cache them
+const normalizationCache = new Map();
+const splitCache = new Map();
function normalizeCssString(cssText) {
- return cssText.replace(/(\/\*[^*]*\*\/)|[\s;]/g, "");
-}
-function splitCssText(cssText, style) {
- const childNodes2 = Array.from(style.childNodes);
+ if (!normalizationCache.has(cssText)) {
+ const normalized = cssText.replace(/(\/\*[^*]*\*\/)|[\s;]/g, '');
+ normalizationCache.set(cssText, normalized);
+ }
+ // we know that the value is in the cache now
+ return normalizationCache.get(cssText);
+}
+/**
+ * Maps the output of stringifyStylesheet to individual text nodes of a <style> element
+ * which occurs when javascript is used to append to the style element
Expand All @@ -51,6 +64,10 @@ index d9c57625633fb87da27fc5948c1b15a7c4e4caa5..472c9f1359baf685279614c474266481
- for (let j = 3; j < textContentNorm.length; j++) {
+ let iterLimit = 0;
+ if (childNodes.length > 1 && cssText && typeof cssText === 'string') {
+ if (splitCache.has(cssText)) {
+ // we know there's a result
+ return splitCache.get(cssText)
+ }
+ let cssTextNorm = normalizeCssString(cssText);
+ const normFactor = cssTextNorm.length / cssText.length;
+ for (let i = 1; i < childNodes.length; i++) {
Expand Down Expand Up @@ -119,16 +136,17 @@ index d9c57625633fb87da27fc5948c1b15a7c4e4caa5..472c9f1359baf685279614c474266481
}
}
break;
@@ -451,7 +512,7 @@ function splitCssText(cssText, style) {
@@ -451,7 +524,8 @@ function splitCssText(cssText, style) {
}
}
}
- splits.push(cssText);
+ splits.push(cssText); // either the full thing if no splits were found, or the last split
+ splitCache.set(cssText, splits);
return splits;
}
function markCssSplits(cssText, style) {
@@ -841,9 +902,14 @@ function serializeElementNode(n2, options) {
@@ -841,9 +915,14 @@ function serializeElementNode(n2, options) {
}
}
if (tagName === "link" && inlineStylesheet) {
Expand All @@ -146,7 +164,7 @@ index d9c57625633fb87da27fc5948c1b15a7c4e4caa5..472c9f1359baf685279614c474266481
let cssText = null;
if (stylesheet) {
cssText = stringifyStylesheet(stylesheet);
@@ -889,7 +955,15 @@ function serializeElementNode(n2, options) {
@@ -889,7 +968,15 @@ function serializeElementNode(n2, options) {
}
}
if (tagName === "dialog" && n2.open) {
Expand All @@ -163,7 +181,7 @@ index d9c57625633fb87da27fc5948c1b15a7c4e4caa5..472c9f1359baf685279614c474266481
}
if (tagName === "canvas" && recordCanvas) {
if (n2.__context === "2d") {
@@ -1112,7344 +1186,249 @@ function serializeNodeWithId(n2, options) {
@@ -1112,7344 +1199,249 @@ function serializeNodeWithId(n2, options) {
return null;
}
if (onSerialize) {
Expand Down Expand Up @@ -7736,7 +7754,7 @@ index d9c57625633fb87da27fc5948c1b15a7c4e4caa5..472c9f1359baf685279614c474266481
class BaseRRNode {
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
constructor(..._args) {
@@ -11451,11 +4430,19 @@ class CanvasManager {
@@ -11451,11 +4443,19 @@ class CanvasManager {
let rafId;
const getCanvas = () => {
const matchedCanvas = [];
Expand All @@ -7761,7 +7779,7 @@ index d9c57625633fb87da27fc5948c1b15a7c4e4caa5..472c9f1359baf685279614c474266481
return matchedCanvas;
};
const takeCanvasSnapshots = (timestamp) => {
@@ -11476,13 +4463,20 @@ class CanvasManager {
@@ -11476,13 +4476,20 @@ class CanvasManager {
context.clear(context.COLOR_BUFFER_BIT);
}
}
Expand All @@ -7786,22 +7804,35 @@ index d9c57625633fb87da27fc5948c1b15a7c4e4caa5..472c9f1359baf685279614c474266481
},
[bitmap]
diff --git a/dist/record.umd.cjs b/dist/record.umd.cjs
index 902c5eca13b2c3e69af25afa682d2e7300372bfc..4da3d8a172b53199f91880229ec5d665bb7d0fd4 100644
index 902c5eca13b2c3e69af25afa682d2e7300372bfc..23fc9fffa6b815da448311dd31cec52c3abeb44f 100644
--- a/dist/record.umd.cjs
+++ b/dist/record.umd.cjs
@@ -473,23 +473,81 @@ function absolutifyURLs(cssText, href) {
function normalizeCssString(cssText) {
return cssText.replace(/(\/\*[^*]*\*\/)|[\s;]/g, "");
@@ -470,26 +470,96 @@ function absolutifyURLs(cssText, href) {
}
);
}
+// these operations can be slow, let's cache them
+const normalizationCache = new Map();
+const splitCache = new Map();
function normalizeCssString(cssText) {
- return cssText.replace(/(\/\*[^*]*\*\/)|[\s;]/g, "");
-}
-function splitCssText(cssText, style) {
- const childNodes2 = Array.from(style.childNodes);
+ if (!normalizationCache.has(cssText)) {
+ const normalized = cssText.replace(/(\/\*[^*]*\*\/)|[\s;]/g, '');
+ normalizationCache.set(cssText, normalized);
+ }
+ // we know that the value is in the cache now
+ return normalizationCache.get(cssText);
+}
+/**
+ * Maps the output of stringifyStylesheet to individual text nodes of a <style> element
+ * which occurs when javascript is used to append to the style element
+ * and may also occur when browsers opt to break up large text nodes
+ * performance needs to be considered, see e.g. #1603
+ */
+export function splitCssText(
+function splitCssText(
+ cssText,
+ style,
+) {
Expand All @@ -7815,6 +7846,10 @@ index 902c5eca13b2c3e69af25afa682d2e7300372bfc..4da3d8a172b53199f91880229ec5d665
- for (let j = 3; j < textContentNorm.length; j++) {
+ let iterLimit = 0;
+ if (childNodes.length > 1 && cssText && typeof cssText === 'string') {
+ if (splitCache.has(cssText)) {
+ // we know there's a result
+ return splitCache.get(cssText)
+ }
+ let cssTextNorm = normalizeCssString(cssText);
+ const normFactor = cssTextNorm.length / cssText.length;
+ for (let i = 1; i < childNodes.length; i++) {
Expand Down Expand Up @@ -7883,12 +7918,13 @@ index 902c5eca13b2c3e69af25afa682d2e7300372bfc..4da3d8a172b53199f91880229ec5d665
}
}
break;
@@ -498,7 +556,7 @@ function splitCssText(cssText, style) {
@@ -498,7 +568,8 @@ function splitCssText(cssText, style) {
}
}
}
- splits.push(cssText);
+ splits.push(cssText); // either the full thing if no splits were found, or the last split
+ splitCache.set(cssText, splits);
return splits;
}
function markCssSplits(cssText, style) {
6 changes: 3 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit d97b413

Please sign in to comment.