Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot read properties of null (reading 'children') - dynamicCSS.ts #603

Open
josepdaniel opened this issue Dec 11, 2024 · 2 comments
Open

Comments

@josepdaniel
Copy link

Hi there, thank you for authoring these utilities.

We have run into a persistent problem when hydrating server-side-rendered react using cssinjs-based components (eg antd-v5) due to the following calls in dynamicCSS.ts.

function findStyles(container: ContainerType) {
  return Array.from(
    (containerCache.get(container) || container).children,
  ).filter(node => node.tagName === 'STYLE') as HTMLStyleElement[];
}

Where container is usually fetched from

function getContainer(option: Options) {
  if (option.attachTo) {
    return option.attachTo;
  }

  const head = document.querySelector('head');
  return head || document.body;
}

When hydrating an SSR react app, if there is a mismatch between the client-render and server-render then the client will re-render the component. For frameworks like remix, where the whole document is rendered, document.querySelector('head') and document.body may both be null at the time of rendering, leading to the following error

Uncaught TypeError: Cannot read properties of null (reading 'children')

I believe the following PR, which has already been open for quite some time, will address the bug. So we would like to request considering it for merge. Thank you in advance!

#455

@zombieJ

@josepdaniel josepdaniel changed the title children is not a property of null Cannot read properties of null (reading 'children') - dynamicCSS.ts Dec 11, 2024
@ethos-seth
Copy link

ethos-seth commented Jan 11, 2025

omfg. This issue has been plaguing me! It took me a while to realize it was happening down in rc-util. Thanks for filing this!

An ~18 month old open PR doesn't feel particularly promising. Is there any way to get this merged?

Also @josepdaniel have you found any workarounds?

Edit: For now my solution is a monkeypatch:

diff --git a/node_modules/rc-util/es/Dom/dynamicCSS.js b/node_modules/rc-util/es/Dom/dynamicCSS.js
index 8ddec00..d6c390d 100644
--- a/node_modules/rc-util/es/Dom/dynamicCSS.js
+++ b/node_modules/rc-util/es/Dom/dynamicCSS.js
@@ -31,7 +31,7 @@ function getOrder(prepend) {
  * Find style which inject by rc-util
  */
 function findStyles(container) {
-  return Array.from((containerCache.get(container) || container).children).filter(function (node) {
+  return Array.from((containerCache.get(container) || container)?.children || []).filter(function (node) {
     return node.tagName === 'STYLE';
   });
 }
@@ -56,7 +56,7 @@ export function injectCSS(css) {
   }
   styleNode.innerHTML = css;
   var container = getContainer(option);
-  var firstChild = container.firstChild;
+  var firstChild = container?.firstChild;
   if (prepend) {
     // If is queue `prepend`, it will prepend first style and then append rest style
     if (isPrependQueue) {
@@ -77,9 +77,11 @@ export function injectCSS(css) {
     }
 
     // Use `insertBefore` as `prepend`
-    container.insertBefore(styleNode, firstChild);
+    if (firstChild) {
+      container.insertBefore(styleNode, firstChild);
+    }
   } else {
-    container.appendChild(styleNode);
+    container?.appendChild(styleNode);
   }
   return styleNode;
 }
@@ -95,7 +97,7 @@ export function removeCSS(key) {
   var existNode = findExistNode(key, option);
   if (existNode) {
     var container = getContainer(option);
-    container.removeChild(existNode);
+    container?.removeChild(existNode);
   }
 }
 
@@ -110,7 +112,7 @@ function syncRealContainer(container, option) {
     var placeholderStyle = injectCSS('', option);
     var parentNode = placeholderStyle.parentNode;
     containerCache.set(container, parentNode);
-    container.removeChild(placeholderStyle);
+    container?.removeChild(placeholderStyle);
   }
 }
 
diff --git a/node_modules/rc-util/lib/Dom/dynamicCSS.js b/node_modules/rc-util/lib/Dom/dynamicCSS.js
index 95a5191..1303898 100644
--- a/node_modules/rc-util/lib/Dom/dynamicCSS.js
+++ b/node_modules/rc-util/lib/Dom/dynamicCSS.js
@@ -41,7 +41,7 @@ function getOrder(prepend) {
  * Find style which inject by rc-util
  */
 function findStyles(container) {
-  return Array.from((containerCache.get(container) || container).children).filter(function (node) {
+  return Array.from((containerCache.get(container) || container)?.children || []).filter(function (node) {
     return node.tagName === 'STYLE';
   });
 }
@@ -66,7 +66,7 @@ function injectCSS(css) {
   }
   styleNode.innerHTML = css;
   var container = getContainer(option);
-  var firstChild = container.firstChild;
+  var firstChild = container?.firstChild;
   if (prepend) {
     // If is queue `prepend`, it will prepend first style and then append rest style
     if (isPrependQueue) {
@@ -87,9 +87,11 @@ function injectCSS(css) {
     }
 
     // Use `insertBefore` as `prepend`
-    container.insertBefore(styleNode, firstChild);
+    if (firstChild) {
+      container.insertBefore(styleNode, firstChild);
+    }
   } else {
-    container.appendChild(styleNode);
+    container?.appendChild(styleNode);
   }
   return styleNode;
 }
@@ -105,7 +107,7 @@ function removeCSS(key) {
   var existNode = findExistNode(key, option);
   if (existNode) {
     var container = getContainer(option);
-    container.removeChild(existNode);
+    container?.removeChild(existNode);
   }
 }
 
@@ -120,7 +122,7 @@ function syncRealContainer(container, option) {
     var placeholderStyle = injectCSS('', option);
     var parentNode = placeholderStyle.parentNode;
     containerCache.set(container, parentNode);
-    container.removeChild(placeholderStyle);
+    container?.removeChild(placeholderStyle);
   }
 }

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

No branches or pull requests

2 participants