head icon indicating copy to clipboard operation
head copied to clipboard

Fix setAttrs runs before head is ready

Open christian4leaflabs opened this issue 1 year ago • 3 comments

:link: Linked issue

resolve #75

:question: Type of change

  • [ ] :book: Documentation (updates to the documentation or readme)
  • [x] :lady_beetle: Bug fix (a non-breaking change that fixes an issue)
  • [ ] :ok_hand: Enhancement (improving an existing functionality like performance)
  • [ ] :sparkles: New feature (a non-breaking change that adds functionality)
  • [ ] :warning: Breaking change (fix or feature that would cause existing functionality to change)

:books: Description

Nuxt3 runs the updateDOM function directly before the head has htmlAttrs, and this is causing to clear existing attributes in the head; this happened during hydration

christian4leaflabs avatar Jul 28 '22 19:07 christian4leaflabs

Please revert the format changes. Thanks.

antfu avatar Jul 29 '22 08:07 antfu

Please revert the format changes. Thanks.

Done :+1:

christian4leaflabs avatar Jul 29 '22 13:07 christian4leaflabs

Could you add some tests to it?

antfu avatar Jul 29 '22 14:07 antfu

I tested this by patching it in my project (using yarn patch), and it didn't fix the issue. See attached video (the background is initially green to emphasize the flash).

main.scss

html {
  background-color: #0f0;
  color: var(--text);
}

Then, in the Nuxt code:

useHead({
  meta: 'theme' in reelOrEmbed ? generateOgMeta(reelOrEmbed) : [],
  style: [
    {
      type: 'text/css',
      children: `
        :root {
          --background: ${theme.background};
          --background-contrast: ${bgContrastColor.value.toHex8String()};
          --faded-overlay: ${fadedOverlay};
          --text: ${theme.text};
          ${theme.link ? '--link: ' + theme.link + ';' : ''}
          --primary: ${theme.primary};
          --primary-faded: ${primaryFadedColor.toHex8String()};
        }
      `,
    },
  ],
});

https://user-images.githubusercontent.com/12532733/187232695-14d97813-ec03-4e45-b320-f517e87b36a5.mp4

ffxsam avatar Aug 29 '22 15:08 ffxsam

Hey @christian4leaflabs, If you're still interested in solving this one could you address the above comment and maybe add some tests in the nuxt3 e2e

Will close for now as it seems stale but please re-open if / when changes are made :)

harlan-zw avatar Sep 19 '22 05:09 harlan-zw

This isn't stale, it's still an issue. And there's no currently proven fix that I'm aware of.

ffxsam avatar Sep 19 '22 18:09 ffxsam

The issue isn't stale (https://github.com/vueuse/head/issues/75), the PR is though as it hasn't been updated since July without any progress towards merging it.

harlan-zw avatar Sep 20 '22 03:09 harlan-zw

This PR doesn't solve the issue, anyway (I tried it). The only thing that worked for me was my debouncer to limit how many times the update method can be called, and this prevents the flicker.

ffxsam avatar Sep 20 '22 04:09 ffxsam

Thanks for the details @ffxsam, would you mind sharing this code snippet in the issue https://github.com/vueuse/head/issues/75, it will be helpful when I attempt to fix it.

harlan-zw avatar Sep 20 '22 04:09 harlan-zw

@harlan-zw Of course! I can't guarantee it's the most elegant. 😅 I was in a hurry and needed a fix, but maybe you can improve upon it.

Keep in mind, this is a yarn patch, so it's on the bundled index.mjs file, not the original source code. Also, this patch includes the fix for the &amp issue.

Diff file
diff --git a/dist/index.mjs b/dist/index.mjs
index 481b7343c20357bc198ebec977c5daaff0c25e24..ecfcaf61faece3b0a3a91fd14e60d7f20c947f10 100644
--- a/dist/index.mjs
+++ b/dist/index.mjs
@@ -57,8 +57,18 @@ var createElement = (tag, attrs, document) => {
   return el;
 };

+var debounce = (fn, delay = 0) => {
+  let timer;
+  return (...args) => {
+    clearTimeout(timer);
+    timer = setTimeout(() => {
+      fn(...args);
+    }, delay);
+  };
+};
+
 // src/stringify-attrs.ts
-var htmlEscape = (str) => str.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&#39;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
+var htmlEscape = (str) => str.replace(/"/g, "&quot;").replace(/'/g, "&#39;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
 var stringifyAttrs = (attributes) => {
   const handledAttributes = [];
   for (let [key, value] of Object.entries(attributes)) {
@@ -300,7 +310,7 @@ var createHead = (initHeadObject) => {
     removeHeadObjs(objs) {
       allHeadObjs = allHeadObjs.filter((_objs) => _objs !== objs);
     },
-    updateDOM(document = window.document) {
+    updateDOM: debounce((document = window.document) => {
       let title;
       let htmlAttrs = {};
       let bodyAttrs = {};
@@ -332,8 +342,8 @@ var createHead = (initHeadObject) => {
       }
       previousTags.clear();
       Object.keys(actualTags).forEach((i) => previousTags.add(i));
-    }
-  };
+    }, 500),
+  }
   return head;
 };
 var IS_BROWSER = typeof window !== "undefined";
</details>

ffxsam avatar Sep 20 '22 04:09 ffxsam