#Preserve dynamic <links> and <scripts> in <HEAD> while using full site view transitions

21 messages · Page 1 of 1 (latest)

umbral lark
#

I am using Astro.js as a container in microfrontend architecture. Each page download microfrontend (runtime) and inject css and js into the <head>. The problem is, that I am using code splitting. The chunks are injecting dynamic css files into the <head>. Whenever I go to the another route and back with full site view transitions (SPA mode), the <links> are missing. I was experimenting with transition:persist, but it is not suitable for this case. What options do I have?

mortal badge
crude talon
#

Hi @umbral lark 👋 The ClientRouter works with the static HTML files. When you navigate to another route, it loads that DOM and changes the current DOM to reflect the new one. Then it runs the new scripts. If those scripts also manipulate the DOM results may be other than expected. As Adam said, having a minimal reproduction will really help a lot to understand how to find a solution for your case.

umbral lark
#

You can see, that the microfrontend application is rendered, but the styles are missing

crude talon
#

I’ll take look…

crude talon
#

@umbral lark, mounting the app works fine when you revisit / after /page. The reason for the CSS not being re-inserted into the head on mount is buried somewhere in that 90k minified js. I assume, it contains internal state that 2knows" that the stylesheet is still there and does not know that the ClientRouter removed it as it was not in the loaded DOM.
Maybe you can override Astro's swap function, disabling the part that removes stylesheets. But this makes only sense if the script would remove them when they are not needed, which i doubt.

Because the problem here arises from shared state across pages, i would replace <ClientRouter /> with
<style>@view-transition{navigation: auto}</style> and use browser native view transitions where supported.

mild tendonBOT
#
If your issue is resolved, please help by doing the following two steps:
  1. From the ellipses (3-dot menu) in the top-right corner of the post (not the first message), edit the tags to include the Solved tag.
  2. From the same ellipses, select Close Post.
    Your post will still be available to search and can be re-opened simply by replying in it. Closing a post moves it down with older posts, so we can more easily focus on issues that still need to be resolved.
    Thank you for your help!
umbral lark
#

I would like to prefer SPA mode because of microfrontends optimization. I would rather clean styles whenever they are not needed. How can I override the swap function?

umbral lark
#

Finally I solved it with astro:before-swap as you suggest:

  <script>
    import { swapFunctions } from 'astro:transitions/client';

    function swapMainOnly(doc) {
      console.error('swapping')
      swapFunctions.deselectScripts(doc);
      swapFunctions.swapRootAttributes(doc);
      // swapFunctions.swapHeadElements(doc);
      const restoreFocusFunction = swapFunctions.saveFocus();
      const newMain = doc.querySelector('main');
      const oldMain = document.querySelector('main');
      if (newMain && oldMain) {
        swapFunctions.swapBodyElement(newMain, oldMain);
      } else {
        swapFunctions.swapBodyElement(doc.body, document.body);
      }

      restoreFocusFunction();
    }


    document.addEventListener('astro:before-swap', (e) => {
      e.swap = () => swapMainOnly(e.newDocument);
    });
    </script>

Not ideal because even title is not replaced. But I will create some internalSwapHeahElemets function.
Thank you very much for help!

crude talon
#

Sorry for just coming late to the party. Yes, if the script takes care for the header, that is an excellent solution. As you said, tweaking the head swap for the title shouldn't be too hard. Happy you found that solution and the docs link. and thank you for documenting it here for others to follow 😉 👍

umbral lark
#

I was optimizing the solution and the best approach is probably push the links to the new document I would like to exchange:

    <script>
      import { swapFunctions } from 'astro:transitions/client';

      document.addEventListener('astro:before-swap', (e) => {
        e.swap = () => swap(e.newDocument);
      });

      function swap(doc) {
        swapFunctions.deselectScripts(doc);
        swapFunctions.swapRootAttributes(doc);

        document.querySelectorAll('link[rel="stylesheet"]').forEach((link) => {
          doc.head.append(link)
        });

        swapFunctions.swapHeadElements(doc);
          const restoreFocusFunction = swapFunctions.saveFocus();
        swapFunctions.swapBodyElement(doc.body, document.body);
          restoreFocusFunction();
      }
    </script>

With that, I will keep using swapHeadElements together with persistedHeadElement directly from astro without mirroring the functionality to my codebase

umbral lark
#

I even simplifed this to:

<script>
  document.addEventListener('astro:before-swap', (e) => {
    document.querySelectorAll('link[rel="stylesheet"]').forEach((link) => {
      e.newDocument.head.append(link)
    });
  });
</script>
crude talon
#

Perfect!

#

It is most fun to see how a solution just gets better and better even if I am always too late to really support 😳

umbral lark
#

You were a really big help! I would not notice in transition view documentation that I can use swap functions. Again, thak you very much!