<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Florian Rappl</title>
    <description>The latest articles on Forem by Florian Rappl (@florianrappl).</description>
    <link>https://forem.com/florianrappl</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F268296%2Feb6a1ad0-17d3-4302-9c44-a263a666b072.jpg</url>
      <title>Forem: Florian Rappl</title>
      <link>https://forem.com/florianrappl</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/florianrappl"/>
    <language>en</language>
    <item>
      <title>netpack</title>
      <dc:creator>Florian Rappl</dc:creator>
      <pubDate>Thu, 09 Jan 2025 23:51:37 +0000</pubDate>
      <link>https://forem.com/florianrappl/netpack-5ej4</link>
      <guid>https://forem.com/florianrappl/netpack-5ej4</guid>
      <description>&lt;p&gt;This will be a short post... but hopefully with a longer one following up.&lt;/p&gt;

&lt;p&gt;During my winter vacation I got some time to do one experiment:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can web tooling created using C#/.NET yield comparable performance to Rust / Go / Zig ...?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So I did some coding... (that you can &lt;a href="https://github.com/FlorianRappl/netpack" rel="noopener noreferrer"&gt;find on GitHub&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  The Process
&lt;/h2&gt;

&lt;p&gt;I started with a crude bundler logic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open files&lt;/li&gt;
&lt;li&gt;Read their content&lt;/li&gt;
&lt;li&gt;Use a regular expression to detect, e.g., import statements in JS files&lt;/li&gt;
&lt;li&gt;Resolve linked modules&lt;/li&gt;
&lt;li&gt;Open resolved / existing package.json files to identify module paths&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result was easy: Using AoT (ahead-of-time compilation) .NET can certainly be used for highly performing web projects.&lt;/p&gt;

&lt;p&gt;So I continued a bit with the experiment; replacing regular expressions with actual code understanding.&lt;/p&gt;

&lt;h2&gt;
  
  
  TLDR; Results
&lt;/h2&gt;

&lt;p&gt;The answer is: yes! 🤯&lt;/p&gt;

&lt;p&gt;The bundler is at the moment feature-incomplete, but the first results are quite strong. The benchmarks shown in the &lt;a href="https://github.com/FlorianRappl/netpack" rel="noopener noreferrer"&gt;README&lt;/a&gt; indicate that the performance is definitely in the same ballpark as other tools. So fast enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  More Details
&lt;/h2&gt;

&lt;p&gt;Personally, I think that C#/.NET is much less complicated than Rust and more powerful than Go. It comes with some drawbacks as well - not gonna lie.&lt;/p&gt;

&lt;p&gt;The main reason why C#/.NET can be viable in that space is AoT. Without AoT the startup performance (as well as runtime requirements) is killing the whole idea.&lt;/p&gt;

&lt;p&gt;AoT, on the other hand, comes with some challenges. Some libraries cannot be used or require some work to be integrated. Hence, some of the flexibility of .NET cannot be used.&lt;/p&gt;

&lt;p&gt;For the largest test project also used by tools such as rspack we get these results:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwc9g850i2pseizq9klpi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwc9g850i2pseizq9klpi.png" alt="Bundler performance" width="700" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that even the bundler is feature incomplete, it is crafted enough to produce a valid result on the project. So even though all results are at the moment preliminary there is at least some validity to it.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Test&lt;/th&gt;
&lt;th&gt;esbuild&lt;/th&gt;
&lt;th&gt;rspack&lt;/th&gt;
&lt;th&gt;Vite&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;netpack&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Small lib&lt;/td&gt;
&lt;td&gt;326ms&lt;/td&gt;
&lt;td&gt;611ms&lt;/td&gt;
&lt;td&gt;601ms&lt;/td&gt;
&lt;td&gt;359ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Small project&lt;/td&gt;
&lt;td&gt;670ms&lt;/td&gt;
&lt;td&gt;912ms&lt;/td&gt;
&lt;td&gt;1658ms&lt;/td&gt;
&lt;td&gt;418ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Medium project&lt;/td&gt;
&lt;td&gt;1931ms&lt;/td&gt;
&lt;td&gt;2877ms&lt;/td&gt;
&lt;td&gt;10601ms&lt;/td&gt;
&lt;td&gt;974ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Large project&lt;/td&gt;
&lt;td&gt;2189ms&lt;/td&gt;
&lt;td&gt;2422ms&lt;/td&gt;
&lt;td&gt;13710ms&lt;/td&gt;
&lt;td&gt;1357ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So yes, netpack already beats the competition and even has potential for even better performance. While it can be optimized further, it will also loose some performance when things such as sourcemaps or tree shaking are introduced. Right now I am positive that in total it should be around the same as of now due to the potential optimizations (such as streaming in the JS AST generation).&lt;/p&gt;

&lt;p&gt;The biggest hurdle at the moment is that it only supports JS(X) - no TypeScript yet (it tries to parse these files, but once types are used it will fail). It would be "fairly" easy to support, but I would need to fork &lt;a href="https://github.com/adams85/acornima/" rel="noopener noreferrer"&gt;Acornima&lt;/a&gt; for that and that's something I'd only do if there is enough buzz around the project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Outlook
&lt;/h2&gt;

&lt;p&gt;There are many more things that would be superb to get into this. Some basics need to be cleared first though. Things such as sourcemaps, TypeScript support, or maybe a configuration system would be great.&lt;/p&gt;

&lt;p&gt;There are some things in this experiment that no other bundler does. For instance, if your HTML entry point has an importmap, then the entries in the importmap are &lt;em&gt;automatically&lt;/em&gt; taken as externals. Likewise, you can set certain dependencies as shared - in this case there are automatically importmap entries / an importmap created in the resulting HTML. Quite neat.&lt;/p&gt;

&lt;p&gt;In the future the bundler will have native (i.e., out-of-the-box) support for SASS, CSS modules, CSS-in-JS, as well as module federation and native federation.&lt;/p&gt;

&lt;p&gt;What are your thoughts? Do you think this is a viable idea or just trash? Is a fast .NET-native bundler with sensible defaults something we need?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>dotnet</category>
      <category>javascript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Great edition - thanks to all the authors for their hard work!</title>
      <dc:creator>Florian Rappl</dc:creator>
      <pubDate>Wed, 04 Dec 2024 08:31:48 +0000</pubDate>
      <link>https://forem.com/florianrappl/great-edition-thanks-to-all-the-authors-for-their-hard-work-4mm5</link>
      <guid>https://forem.com/florianrappl/great-edition-thanks-to-all-the-authors-for-their-hard-work-4mm5</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/florianrappl" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F268296%2Feb6a1ad0-17d3-4302-9c44-a263a666b072.jpg" alt="florianrappl"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/florianrappl/whats-hot-in-web-dev-42ng" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;What's Hot in Web Dev?&lt;/h2&gt;
      &lt;h3&gt;Florian Rappl ・ Dec 4&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#frontend&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#node&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>What's Hot in Web Dev?</title>
      <dc:creator>Florian Rappl</dc:creator>
      <pubDate>Wed, 04 Dec 2024 08:31:02 +0000</pubDate>
      <link>https://forem.com/florianrappl/whats-hot-in-web-dev-42ng</link>
      <guid>https://forem.com/florianrappl/whats-hot-in-web-dev-42ng</guid>
      <description>&lt;p&gt;This year I started a new series on LinkedIn - "Advanced Links for Frontend". Each issue has 10 links to outstanding posts / articles. This bundle contains the links from the last 5 issues (issue 66 to issue 70).&lt;/p&gt;

&lt;p&gt;I hope you enjoy this collection. Let me know in the comments which of these articles is your favorite (and why).&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 66
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;How Bun supports V8 APIs without using V8 (part 2)&lt;/strong&gt; (&lt;a href="https://bun.sh/blog/how-bun-supports-v8-apis-without-using-v8-part-2" rel="noopener noreferrer"&gt;https://bun.sh/blog/how-bun-supports-v8-apis-without-using-v8-part-2&lt;/a&gt;) by Ben Grant&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the best React Native list component?&lt;/strong&gt; (&lt;a href="https://expo.dev/blog/what-is-the-best-react-native-list-component" rel="noopener noreferrer"&gt;https://expo.dev/blog/what-is-the-best-react-native-list-component&lt;/a&gt;) by Simon Grimm&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Centering things: a solved problem?&lt;/strong&gt; (&lt;a href="https://fullystacked.net/centering-things/" rel="noopener noreferrer"&gt;https://fullystacked.net/centering-things/&lt;/a&gt;) by Ollie Williams&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WebVM 2.0: A complete Linux Desktop Environment in the browser via WebAssembly&lt;/strong&gt; (&lt;a href="https://labs.leaningtech.com/blog/webvm-20" rel="noopener noreferrer"&gt;https://labs.leaningtech.com/blog/webvm-20&lt;/a&gt;) by Alessandro Pignotti&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I Followed the Official AWS Amplify Guide and was Charged $1,100&lt;/strong&gt; (&lt;a href="https://elliott-king.github.io/2024/10/amplify-overcharge/" rel="noopener noreferrer"&gt;https://elliott-king.github.io/2024/10/amplify-overcharge/&lt;/a&gt;) by Elliott King&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Different (and Modern) Ways to Toggle Content&lt;/strong&gt; (&lt;a href="https://css-tricks.com/the-different-and-modern-ways-to-toggle-content/" rel="noopener noreferrer"&gt;https://css-tricks.com/the-different-and-modern-ways-to-toggle-content/&lt;/a&gt;) by Daniel Schwarz&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using Typescript in node.js scripts without actually writing Typescript&lt;/strong&gt; (&lt;a href="https://www.jonathancreamer.com/using-typescript-in-node-js-scripts-without-actually-writing-typescript/" rel="noopener noreferrer"&gt;https://www.jonathancreamer.com/using-typescript-in-node-js-scripts-without-actually-writing-typescript/&lt;/a&gt;) by Jonathan Creamer&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Overflow Clip&lt;/strong&gt; (&lt;a href="https://ishadeed.com/article/overflow-clip/" rel="noopener noreferrer"&gt;https://ishadeed.com/article/overflow-clip/&lt;/a&gt;) by Ahmad Shadeed&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conditional Props in React Using Type Discrimination&lt;/strong&gt; (&lt;a href="https://elanmed.dev/blog/conditional-props-using-type-discrimination" rel="noopener noreferrer"&gt;https://elanmed.dev/blog/conditional-props-using-type-discrimination&lt;/a&gt;) by Elan Medoff&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Micro Components - a different approach to a simpler component-based web&lt;/strong&gt; (&lt;a href="https://www.wearedevelopers.com/magazine/micro-components---an-alternative-to-web-components-and-frameworks/" rel="noopener noreferrer"&gt;https://www.wearedevelopers.com/magazine/micro-components---an-alternative-to-web-components-and-frameworks/&lt;/a&gt;) by Chris Heilmann&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 67
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;JavaScript's ??= Operator: Default Values Made Simple&lt;/strong&gt; (&lt;a href="https://www.trevorlasn.com/blog/javascript-nullish-coalescing-assignment-operator" rel="noopener noreferrer"&gt;https://www.trevorlasn.com/blog/javascript-nullish-coalescing-assignment-operator&lt;/a&gt;) by Trevor Lasn&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fit-to-Width Text: A New Technique&lt;/strong&gt; (&lt;a href="https://kizu.dev/fit-to-width/" rel="noopener noreferrer"&gt;https://kizu.dev/fit-to-width/&lt;/a&gt;) by Roman Komarov&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Self-contained Executable Programs with Deno Compile&lt;/strong&gt; (&lt;a href="https://deno.com/blog/deno-compile-executable-programs" rel="noopener noreferrer"&gt;https://deno.com/blog/deno-compile-executable-programs&lt;/a&gt;) by Ryan Dahl and Andy Jiang&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;New in React 19 - Pre-warming&lt;/strong&gt; (&lt;a href="https://github.com/facebook/react/issues/29898" rel="noopener noreferrer"&gt;https://github.com/facebook/react/issues/29898&lt;/a&gt;) by Ricky Hanlon&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Will we care about frameworks in the future?&lt;/strong&gt; (&lt;a href="https://paul.kinlan.me/will-we-care-about-frameworks-in-the-future/" rel="noopener noreferrer"&gt;https://paul.kinlan.me/will-we-care-about-frameworks-in-the-future/&lt;/a&gt;) by Paul Kinlan&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Introducing the vlt Package Manager &amp;amp; Serverless Registry&lt;/strong&gt; (&lt;a href="https://blog.vlt.sh/blog/introducing-vlt-and-vsr" rel="noopener noreferrer"&gt;https://blog.vlt.sh/blog/introducing-vlt-and-vsr&lt;/a&gt;) by Darcy Clark et al.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Saga Pattern in Elixir&lt;/strong&gt; (&lt;a href="https://peterullrich.com/saga-pattern-in-elixir" rel="noopener noreferrer"&gt;https://peterullrich.com/saga-pattern-in-elixir&lt;/a&gt;) by Peter Ullrich&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Generating Random Mazes with JavaScript&lt;/strong&gt; (&lt;a href="https://cloudfour.com/thinks/generating-random-mazes-with-javascript/" rel="noopener noreferrer"&gt;https://cloudfour.com/thinks/generating-random-mazes-with-javascript/&lt;/a&gt;) by Paul Hebert&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Beautiful focus outlines&lt;/strong&gt; (&lt;a href="https://medienbaecker.com/articles/focus-outlines" rel="noopener noreferrer"&gt;https://medienbaecker.com/articles/focus-outlines&lt;/a&gt;) by Thomas Günther&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Tragedy of Running an Old Node Project&lt;/strong&gt; (&lt;a href="https://abdisalan.com/posts/tragedy-running-old-node-project" rel="noopener noreferrer"&gt;https://abdisalan.com/posts/tragedy-running-old-node-project&lt;/a&gt;) by Abdisalan Mohamud&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 68
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Long Frames and INP: Understanding Post-Load Performance&lt;/strong&gt; (&lt;a href="https://dev.to/viniciusdallacqua/long-frames-and-inp-understanding-post-load-performance-2maa"&gt;https://dev.to/viniciusdallacqua/long-frames-and-inp-understanding-post-load-performance-2maa&lt;/a&gt;) by &lt;a class="mentioned-user" href="https://dev.to/viniciusdallacqua"&gt;@viniciusdallacqua&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reporting Core Web Vitals With The Performance API&lt;/strong&gt; (&lt;a href="https://www.smashingmagazine.com/2024/02/reporting-core-web-vitals-performance-api/" rel="noopener noreferrer"&gt;https://www.smashingmagazine.com/2024/02/reporting-core-web-vitals-performance-api/&lt;/a&gt;) by Geoff Graham&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;React Router v7&lt;/strong&gt; (&lt;a href="https://remix.run/blog/react-router-v7" rel="noopener noreferrer"&gt;https://remix.run/blog/react-router-v7&lt;/a&gt;) by Michael Jackson&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Shadow DOM is in the front&lt;/strong&gt; (&lt;a href="https://abstract.properties/the-shadow-dom-is-in-the-front.html" rel="noopener noreferrer"&gt;https://abstract.properties/the-shadow-dom-is-in-the-front.html&lt;/a&gt;) by Sufian Rhazi&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tailwind CSS v4.0 Beta 1&lt;/strong&gt; (&lt;a href="https://tailwindcss.com/blog/tailwindcss-v4-beta" rel="noopener noreferrer"&gt;https://tailwindcss.com/blog/tailwindcss-v4-beta&lt;/a&gt;) by Adam Wathan&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Announcing TypeScript 5.7&lt;/strong&gt; (&lt;a href="https://devblogs.microsoft.com/typescript/announcing-typescript-5-7/" rel="noopener noreferrer"&gt;https://devblogs.microsoft.com/typescript/announcing-typescript-5-7/&lt;/a&gt;) by Daniel Rosenwasser&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Handling Cookies is a Minefield&lt;/strong&gt; (&lt;a href="https://grayduck.mn/2024/11/21/handling-cookies-is-a-minefield/" rel="noopener noreferrer"&gt;https://grayduck.mn/2024/11/21/handling-cookies-is-a-minefield/&lt;/a&gt;) by April King&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This Website is Hosted on Bluesky&lt;/strong&gt; (&lt;a href="https://danielmangum.com/posts/this-website-is-hosted-on-bluesky/" rel="noopener noreferrer"&gt;https://danielmangum.com/posts/this-website-is-hosted-on-bluesky/&lt;/a&gt;) by Daniel Mangum&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zero Disk Architecture&lt;/strong&gt; (&lt;a href="https://avi.im/blag/2024/zero-disk-architecture/" rel="noopener noreferrer"&gt;https://avi.im/blag/2024/zero-disk-architecture/&lt;/a&gt;) by Avinash Sajjanshetty&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Google’s Chrome Worth Up to $20 Billion If Judge Orders Sale&lt;/strong&gt; (&lt;a href="https://www.bloomberg.com/news/articles/2024-11-18/doj-will-push-google-to-sell-off-chrome-to-break-search-monopoly" rel="noopener noreferrer"&gt;https://www.bloomberg.com/news/articles/2024-11-18/doj-will-push-google-to-sell-off-chrome-to-break-search-monopoly&lt;/a&gt;) by Leah Nylen and Josh Sisco&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 69
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Webflow Design Language: Bridging The Gap Between Design &amp;amp; Code&lt;/strong&gt; (&lt;a href="https://webflow.com/blog/webflow-design-language" rel="noopener noreferrer"&gt;https://webflow.com/blog/webflow-design-language&lt;/a&gt;) by Merrick Christensen&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Building Reddit’s Frontend with Vite&lt;/strong&gt; (&lt;a href="https://www.reddit.com/r/RedditEng/comments/1dhztk8/building_reddits_frontend_with_vite/" rel="noopener noreferrer"&gt;https://www.reddit.com/r/RedditEng/comments/1dhztk8/building_reddits_frontend_with_vite/&lt;/a&gt;) by Jim Simon&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interop and Hard Problems&lt;/strong&gt; (&lt;a href="https://bkardell.com/blog/debt.html" rel="noopener noreferrer"&gt;https://bkardell.com/blog/debt.html&lt;/a&gt;) by Brian Kardell&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vite 6.0 is out!&lt;/strong&gt; (&lt;a href="https://vite.dev/blog/announcing-vite6.html" rel="noopener noreferrer"&gt;https://vite.dev/blog/announcing-vite6.html&lt;/a&gt;) by Evan You&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Complete Guide To Live Validation UX&lt;/strong&gt; (&lt;a href="https://www.smashingmagazine.com/2022/09/inline-validation-web-forms-ux/" rel="noopener noreferrer"&gt;https://www.smashingmagazine.com/2022/09/inline-validation-web-forms-ux/&lt;/a&gt;) by Vitaly Friedman&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Placeholders in Form Fields Are Harmful&lt;/strong&gt; (&lt;a href="https://www.nngroup.com/articles/form-design-placeholders/" rel="noopener noreferrer"&gt;https://www.nngroup.com/articles/form-design-placeholders/&lt;/a&gt;) by Katie Sherwin&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Browser APIs: Must-Know Secrets for Every Frontend Developer!&lt;/strong&gt; (&lt;a href="https://dev.to/mukhilpadmanabhan/browser-apis-must-know-secrets-for-every-frontend-developer-55lk"&gt;https://dev.to/mukhilpadmanabhan/browser-apis-must-know-secrets-for-every-frontend-developer-55lk&lt;/a&gt;) by &lt;a class="mentioned-user" href="https://dev.to/mukhilpadmanabhan"&gt;@mukhilpadmanabhan&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I learned React Native as a web developer, and I got everything wrong&lt;/strong&gt; (&lt;a href="https://fernandorojo.co/mistakes" rel="noopener noreferrer"&gt;https://fernandorojo.co/mistakes&lt;/a&gt;) by Fernando Rojo&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why TanStack Start is Ditching Adapters&lt;/strong&gt; (&lt;a href="https://tanstack.com/blog/why-tanstack-start-is-ditching-adapters" rel="noopener noreferrer"&gt;https://tanstack.com/blog/why-tanstack-start-is-ditching-adapters&lt;/a&gt;) by Tanner Linsley&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vitest vs. Jest&lt;/strong&gt; (&lt;a href="https://www.speakeasy.com/post/vitest-vs-jest" rel="noopener noreferrer"&gt;https://www.speakeasy.com/post/vitest-vs-jest&lt;/a&gt;) by Nolan Sullivan&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 70
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Why am I writing a JavaScript toolchain in Zig?&lt;/strong&gt; (&lt;a href="https://injuly.in/blog/announcing-jam/index.html" rel="noopener noreferrer"&gt;https://injuly.in/blog/announcing-jam/index.html&lt;/a&gt;) by Srijan Paul&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;November 20, 2024 Release&lt;/strong&gt; (&lt;a href="https://react-spectrum.adobe.com/releases/2024-11-20.html" rel="noopener noreferrer"&gt;https://react-spectrum.adobe.com/releases/2024-11-20.html&lt;/a&gt;) by React Aria&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Effortless UI Spring Animations: A Two-Parameter Approach&lt;/strong&gt; (&lt;a href="https://www.kvin.me/posts/effortless-ui-spring-animations" rel="noopener noreferrer"&gt;https://www.kvin.me/posts/effortless-ui-spring-animations&lt;/a&gt;) by Kevin Grajeda&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If Not React, Then What?&lt;/strong&gt; (&lt;a href="https://infrequently.org/2024/11/if-not-react-then-what/" rel="noopener noreferrer"&gt;https://infrequently.org/2024/11/if-not-react-then-what/&lt;/a&gt;) by Alex Russell&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Comparing AWS S3 with Cloudflare R2: Price, Performance and User Experience&lt;/strong&gt; (&lt;a href="https://kerkour.com/aws-s3-vs-cloudflare-r2-price-performance-user-experience" rel="noopener noreferrer"&gt;https://kerkour.com/aws-s3-vs-cloudflare-r2-price-performance-user-experience&lt;/a&gt;) by Sylvain Kerkour&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Must-Have Obsidian plugins for 2025&lt;/strong&gt; (&lt;a href="https://www.dsebastien.net/2022-10-19-the-must-have-obsidian-plugins/" rel="noopener noreferrer"&gt;https://www.dsebastien.net/2022-10-19-the-must-have-obsidian-plugins/&lt;/a&gt;) by Sebastien Dubois&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Layered Approach to Speculation Rules&lt;/strong&gt; (&lt;a href="https://csswizardry.com/2024/12/a-layered-approach-to-speculation-rules/" rel="noopener noreferrer"&gt;https://csswizardry.com/2024/12/a-layered-approach-to-speculation-rules/&lt;/a&gt;) by Harry Roberts&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nothing Is Something&lt;/strong&gt; (&lt;a href="https://blog.jim-nielsen.com/2024/nothing-is-something/" rel="noopener noreferrer"&gt;https://blog.jim-nielsen.com/2024/nothing-is-something/&lt;/a&gt;) by Jim Nielsen&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Increasing Vite's potential with the Environment API&lt;/strong&gt; (&lt;a href="https://green.sapphi.red/blog/increasing-vites-potential-with-the-environment-api" rel="noopener noreferrer"&gt;https://green.sapphi.red/blog/increasing-vites-potential-with-the-environment-api&lt;/a&gt;) by sapphi-red&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Existential React questions and a perfect Modal Dialog&lt;/strong&gt; (&lt;a href="https://www.developerway.com/posts/hard-react-questions-and-modal-dialog" rel="noopener noreferrer"&gt;https://www.developerway.com/posts/hard-react-questions-and-modal-dialog&lt;/a&gt;) by Nadia Makarevich&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;These are all outstanding articles by masterful authors. I enjoyed reading them all - I hope you did find something in there, too.&lt;/p&gt;

&lt;p&gt;👉 Follow me on &lt;a href="https://www.linkedin.com/in/florian-rappl/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://twitter.com/FlorianRappl" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, &lt;a href="https://bsky.app/profile/florianrappl.bsky.social" rel="noopener noreferrer"&gt;BlueSky&lt;/a&gt;, or here for more to come.&lt;/p&gt;

&lt;p&gt;🙏 Thanks to all the authors and contributors for their hard work!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>node</category>
    </item>
    <item>
      <title>🤯 50 Articles to Become a Web Dev Guru</title>
      <dc:creator>Florian Rappl</dc:creator>
      <pubDate>Fri, 15 Nov 2024 19:15:31 +0000</pubDate>
      <link>https://forem.com/florianrappl/50-articles-to-become-a-web-dev-guru-71e</link>
      <guid>https://forem.com/florianrappl/50-articles-to-become-a-web-dev-guru-71e</guid>
      <description>&lt;p&gt;This year I started a new series on LinkedIn - "Advanced Links for Frontend". Each issue has 10 links to outstanding posts / articles. This bundle contains the links from the last 5 issues (issue 61 to issue 65).&lt;/p&gt;

&lt;p&gt;I hope you enjoy this collection. Let me know in the comments which of these articles is your favorite (and why).&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 61
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Liskov’s Gun: The parallel evolution of React and Web Components&lt;/strong&gt; (&lt;a href="https://www.baldurbjarnason.com/2024/liskovs-gun/" rel="noopener noreferrer"&gt;https://www.baldurbjarnason.com/2024/liskovs-gun/&lt;/a&gt;) by Baldur Bjarnason&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mozilla rebrand takes from early internet aesthetics, to move its cause to reclaim the web&lt;/strong&gt; (&lt;a href="https://www.itsnicethat.com/articles/jkr-mozilla-rebrand-graphic-design-project-240924" rel="noopener noreferrer"&gt;https://www.itsnicethat.com/articles/jkr-mozilla-rebrand-graphic-design-project-240924&lt;/a&gt;) by Ellis Tree&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's New in Ruby on Rails 8&lt;/strong&gt; (&lt;a href="https://blog.appsignal.com/2024/10/07/whats-new-in-ruby-on-rails-8.html" rel="noopener noreferrer"&gt;https://blog.appsignal.com/2024/10/07/whats-new-in-ruby-on-rails-8.html&lt;/a&gt;) by Damilola Olantuji&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A modest critique of Htmx&lt;/strong&gt; (&lt;a href="https://chrisdone.com/posts/htmx-critique/" rel="noopener noreferrer"&gt;https://chrisdone.com/posts/htmx-critique/&lt;/a&gt;) by Chris Done&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTML is for people&lt;/strong&gt; (&lt;a href="https://htmlforpeople.com/" rel="noopener noreferrer"&gt;https://htmlforpeople.com/&lt;/a&gt;) by Blake Watson&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;17 Must-know React Projects for Developers 👩‍💻 🔥&lt;/strong&gt; (&lt;a href="https://dev.to/tolgee_i18n/17-must-know-react-projects-for-developers-28a2"&gt;https://dev.to/tolgee_i18n/17-must-know-react-projects-for-developers-28a2&lt;/a&gt;) by &lt;a class="mentioned-user" href="https://dev.to/anmolbaranwal"&gt;@anmolbaranwal&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The story of web framework Hono, from the creator of Hono&lt;/strong&gt; (&lt;a href="https://blog.cloudflare.com/the-story-of-web-framework-hono-from-the-creator-of-hono/" rel="noopener noreferrer"&gt;https://blog.cloudflare.com/the-story-of-web-framework-hono-from-the-creator-of-hono/&lt;/a&gt;) by Yusuke Wada&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sites Now Become Interactive 50% Faster&lt;/strong&gt; (&lt;a href="https://www.framer.com/blog/sites-interactive-faster/" rel="noopener noreferrer"&gt;https://www.framer.com/blog/sites-interactive-faster/&lt;/a&gt;) by Jacob Groß&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drag to Select&lt;/strong&gt; (&lt;a href="https://www.joshuawootonn.com/react-drag-to-select" rel="noopener noreferrer"&gt;https://www.joshuawootonn.com/react-drag-to-select&lt;/a&gt;) by Joshua Wootonn&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why I’m skeptical of rewriting JavaScript tools in “faster” languages&lt;/strong&gt; (&lt;a href="https://nolanlawson.com/2024/10/20/why-im-skeptical-of-rewriting-javascript-tools-in-faster-languages/" rel="noopener noreferrer"&gt;https://nolanlawson.com/2024/10/20/why-im-skeptical-of-rewriting-javascript-tools-in-faster-languages/&lt;/a&gt;) by Nolan Lawson&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 62
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Our Journey with Caching&lt;/strong&gt; (&lt;a href="https://nextjs.org/blog/our-journey-with-caching" rel="noopener noreferrer"&gt;https://nextjs.org/blog/our-journey-with-caching&lt;/a&gt;) by Sebastian Markbåge&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Offline UX Patterns&lt;/strong&gt; (&lt;a href="https://github.com/Expensify/App/blob/main/contributingGuides/OFFLINE_UX.md" rel="noopener noreferrer"&gt;https://github.com/Expensify/App/blob/main/contributingGuides/OFFLINE_UX.md&lt;/a&gt;) by Expensify&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;World Wide Web Foundation closes so Tim Berners-Lee can spend more time with his protocol&lt;/strong&gt; (&lt;a href="https://www.theregister.com/2024/09/30/world_wide_web_foundation_closes/" rel="noopener noreferrer"&gt;https://www.theregister.com/2024/09/30/world_wide_web_foundation_closes/&lt;/a&gt;) by Thomas Claburn&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;why I'm turning off Firefox ad tracking: the PPA paradox&lt;/strong&gt; (&lt;a href="https://blog.zgp.org/why-turn-off-firefox-ad-tracking/" rel="noopener noreferrer"&gt;https://blog.zgp.org/why-turn-off-firefox-ad-tracking/&lt;/a&gt;) by Don Marti&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hyper-Scale Activated! Ship Your Own FaaS 🤖&lt;/strong&gt; (&lt;a href="https://dev.to/smapiot/hyper-scale-activated-ship-your-own-faas-40kg"&gt;https://dev.to/smapiot/hyper-scale-activated-ship-your-own-faas-40kg&lt;/a&gt;) by &lt;a class="mentioned-user" href="https://dev.to/florianrappl"&gt;@florianrappl&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next.js 15&lt;/strong&gt; (&lt;a href="https://nextjs.org/blog/next-15" rel="noopener noreferrer"&gt;https://nextjs.org/blog/next-15&lt;/a&gt;) by Delba de Oliveira et al&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS Data Center Latencies - Visualized&lt;/strong&gt; (&lt;a href="https://benjdd.com/aws/" rel="noopener noreferrer"&gt;https://benjdd.com/aws/&lt;/a&gt;) by Benjamin Dicken&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where web components shine&lt;/strong&gt; (&lt;a href="https://daverupert.com/2024/10/super-web-components-sunshine/" rel="noopener noreferrer"&gt;https://daverupert.com/2024/10/super-web-components-sunshine/&lt;/a&gt;) by Dave Rupert&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Netlify joins OpenNext&lt;/strong&gt; (&lt;a href="https://www.netlify.com/blog/netlify-joins-opennext/" rel="noopener noreferrer"&gt;https://www.netlify.com/blog/netlify-joins-opennext/&lt;/a&gt;) by Mathias Biilmann&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;New Architecture is here&lt;/strong&gt; (&lt;a href="https://reactnative.dev/blog/2024/10/23/the-new-architecture-is-here" rel="noopener noreferrer"&gt;https://reactnative.dev/blog/2024/10/23/the-new-architecture-is-here&lt;/a&gt;) by The React Team&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 63
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Expo SDK 52 beta is now available&lt;/strong&gt; (&lt;a href="https://expo.dev/changelog/2024/10-24-sdk-52-beta" rel="noopener noreferrer"&gt;https://expo.dev/changelog/2024/10-24-sdk-52-beta&lt;/a&gt;) by Brent Vatne&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That's Not an Abstraction, That's Just a Layer of Indirection&lt;/strong&gt; (&lt;a href="https://fhur.me/posts/2024/thats-not-an-abstraction" rel="noopener noreferrer"&gt;https://fhur.me/posts/2024/thats-not-an-abstraction&lt;/a&gt;) by Fernando Hurtado&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An Early Glimpse of TanStack Start&lt;/strong&gt; (&lt;a href="https://www.youtube.com/watch?v=AuHqwQsf64o" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=AuHqwQsf64o&lt;/a&gt;) by Tanner Lindsey&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How we shrunk our Javascript monorepo git size by 94%&lt;/strong&gt; (&lt;a href="https://www.jonathancreamer.com/how-we-shrunk-our-git-repo-size-by-94-percent/" rel="noopener noreferrer"&gt;https://www.jonathancreamer.com/how-we-shrunk-our-git-repo-size-by-94-percent/&lt;/a&gt;) by Jonathan Creamer&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Making content-aware components using CSS :has(), grid, and quantity queries&lt;/strong&gt; (&lt;a href="https://piccalil.li/blog/making-content-aware-components-using-css-has-grid-and-quantity-queries/" rel="noopener noreferrer"&gt;https://piccalil.li/blog/making-content-aware-components-using-css-has-grid-and-quantity-queries/&lt;/a&gt;) by Eric Bailey&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remix Todo App: Part 1 - Building the App Layout and Structure&lt;/strong&gt; (&lt;a href="https://www.udohjeremiah.com/blog/remix-todo-app-part-1-building-the-app-layout-and-structure" rel="noopener noreferrer"&gt;https://www.udohjeremiah.com/blog/remix-todo-app-part-1-building-the-app-layout-and-structure&lt;/a&gt;) by Udoh Jeremiah&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using Rust in Non-Rust Servers to Improve Performance&lt;/strong&gt; (&lt;a href="https://github.com/pretzelhammer/rust-blog/blob/master/posts/rust-in-non-rust-servers.md" rel="noopener noreferrer"&gt;https://github.com/pretzelhammer/rust-blog/blob/master/posts/rust-in-non-rust-servers.md&lt;/a&gt;) by Pretzelhammer&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interactive Select component using Phoenix LiveView and vanilla JS Hook&lt;/strong&gt; (&lt;a href="https://aurmartin.fr/posts/phoenix-liveview-select/" rel="noopener noreferrer"&gt;https://aurmartin.fr/posts/phoenix-liveview-select/&lt;/a&gt;) by Aurélien Martin&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unleash the Power of Scroll-Driven Animations&lt;/strong&gt; (&lt;a href="https://css-tricks.com/unleash-the-power-of-scroll-driven-animations/" rel="noopener noreferrer"&gt;https://css-tricks.com/unleash-the-power-of-scroll-driven-animations/&lt;/a&gt;) by Geoff Graham&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Incremental adoption of micro-frontends with Cloudflare Workers&lt;/strong&gt; (&lt;a href="https://blog.cloudflare.com/fragment-piercing/" rel="noopener noreferrer"&gt;https://blog.cloudflare.com/fragment-piercing/&lt;/a&gt;) by Peter Bacon Darwin, Dario Piotrowicz, James Culveyhouse, Igor Minar&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 64
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Headless, boneless, skinless &amp;amp; lifeless UI&lt;/strong&gt; (&lt;a href="https://nerdy.dev/headless-boneless-and-skinless-ui" rel="noopener noreferrer"&gt;https://nerdy.dev/headless-boneless-and-skinless-ui&lt;/a&gt;) by Adam Argyle&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On Crafting Painterly Shaders&lt;/strong&gt; (&lt;a href="https://blog.maximeheckel.com/posts/on-crafting-painterly-shaders/" rel="noopener noreferrer"&gt;https://blog.maximeheckel.com/posts/on-crafting-painterly-shaders/&lt;/a&gt;) by Maxime Heckel&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Smarter than 'Ctrl+F': Linking Directly to Web Page Content&lt;/strong&gt; (&lt;a href="https://alfy.blog/2024/10/19/linking-directly-to-web-page-content.html" rel="noopener noreferrer"&gt;https://alfy.blog/2024/10/19/linking-directly-to-web-page-content.html&lt;/a&gt;) by Ahmad Alfy&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simplfying Islands Architecture&lt;/strong&gt; (&lt;a href="https://preactjs.com/blog/simplifying-islands-arch/" rel="noopener noreferrer"&gt;https://preactjs.com/blog/simplifying-islands-arch/&lt;/a&gt;) by Siddharth Gelera&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Going through the “State of CSS” results…&lt;/strong&gt; (&lt;a href="https://www.joshwcomeau.com/email/2024-10-22-css-survey/" rel="noopener noreferrer"&gt;https://www.joshwcomeau.com/email/2024-10-22-css-survey/&lt;/a&gt;) by Josh W. Comeau&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rendering Outlines with a Post-processing Shader&lt;/strong&gt; (&lt;a href="https://www.atomwolf.org/posts/rendering-outlines-with-a-post-processing-shader/" rel="noopener noreferrer"&gt;https://www.atomwolf.org/posts/rendering-outlines-with-a-post-processing-shader/&lt;/a&gt;) by Adam Wolf&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should JavaScript be split into two languages? New Google-driven proposal divides opinion&lt;/strong&gt; (&lt;a href="https://devclass.com/2024/10/22/should-javascript-be-split-into-two-languages-new-google-driven-proposal-divides-opinion/" rel="noopener noreferrer"&gt;https://devclass.com/2024/10/22/should-javascript-be-split-into-two-languages-new-google-driven-proposal-divides-opinion/&lt;/a&gt;) by Tim Anderson&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Introducing Wasmer 5.0&lt;/strong&gt; (&lt;a href="https://wasmer.io/posts/introducing-wasmer-v5" rel="noopener noreferrer"&gt;https://wasmer.io/posts/introducing-wasmer-v5&lt;/a&gt;) by Syrus Akbary&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should masonry be part of CSS grid?&lt;/strong&gt; (&lt;a href="https://ishadeed.com/article/css-grid-masonry/" rel="noopener noreferrer"&gt;https://ishadeed.com/article/css-grid-masonry/&lt;/a&gt;) by Ahmad Shadeed&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recap: Next.js Conf 2024&lt;/strong&gt; (&lt;a href="https://vercel.com/blog/recap-next-js-conf-2024" rel="noopener noreferrer"&gt;https://vercel.com/blog/recap-next-js-conf-2024&lt;/a&gt;) by Lee Robinson, Delba de Oliveira&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 65
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;How headless components became the future for building UI libraries&lt;/strong&gt; (&lt;a href="https://www.subframe.com/blog/how-headless-components-became-the-future-for-building-ui-libraries" rel="noopener noreferrer"&gt;https://www.subframe.com/blog/how-headless-components-became-the-future-for-building-ui-libraries&lt;/a&gt;) by Irvin Zhan&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hyperkit&lt;/strong&gt; (&lt;a href="https://www.chrsgrrtt.com/hyperkit" rel="noopener noreferrer"&gt;https://www.chrsgrrtt.com/hyperkit&lt;/a&gt;) by Chris Garrett&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Converting any website to a React component&lt;/strong&gt; (&lt;a href="https://www.magicpatterns.com/blog/any-website-to-react-component" rel="noopener noreferrer"&gt;https://www.magicpatterns.com/blog/any-website-to-react-component&lt;/a&gt;) by Teddy Ni&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTML Form Validation is heavily underused&lt;/strong&gt; (&lt;a href="https://expressionstatement.com/html-form-validation-is-heavily-underused" rel="noopener noreferrer"&gt;https://expressionstatement.com/html-form-validation-is-heavily-underused&lt;/a&gt;) by everdimension&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using Shadcn UI without a Tailwind Config File&lt;/strong&gt; (&lt;a href="https://www.luisball.com/blog/shadcn-ui-with-tailwind-v4" rel="noopener noreferrer"&gt;https://www.luisball.com/blog/shadcn-ui-with-tailwind-v4&lt;/a&gt;) by Luis Ball&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Debugging Microservices &amp;amp; Distributed Systems&lt;/strong&gt; (&lt;a href="https://sentry.io/resources/debugging-microservices-and-distributed-systems/" rel="noopener noreferrer"&gt;https://sentry.io/resources/debugging-microservices-and-distributed-systems/&lt;/a&gt;) by Sarah Guthals&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RFC: An updated style guide for the year 2024&lt;/strong&gt; (&lt;a href="https://github.com/angular/angular/discussions/58412" rel="noopener noreferrer"&gt;https://github.com/angular/angular/discussions/58412&lt;/a&gt;) by Jeremy Elbourn&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My solar-powered and self-hosted website&lt;/strong&gt; (&lt;a href="https://dri.es/my-solar-powered-and-self-hosted-website" rel="noopener noreferrer"&gt;https://dri.es/my-solar-powered-and-self-hosted-website&lt;/a&gt;) by Dries Buytaert&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTTP Tunnel and Proxy in JavaScript&lt;/strong&gt; (&lt;a href="https://dbushell.com/2024/10/22/http-tunnel-proxy/" rel="noopener noreferrer"&gt;https://dbushell.com/2024/10/22/http-tunnel-proxy/&lt;/a&gt;) by David Bushell&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's a Single-Page App?&lt;/strong&gt; (&lt;a href="https://jakelazaroff.com/words/whats-a-single-page-app/" rel="noopener noreferrer"&gt;https://jakelazaroff.com/words/whats-a-single-page-app/&lt;/a&gt;) by Jake Lazaroff&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;These are all outstanding articles by masterful authors. I enjoyed reading them all - I hope you did find something in there, too.&lt;/p&gt;

&lt;p&gt;👉 Follow me on &lt;a href="https://www.linkedin.com/in/florian-rappl/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://twitter.com/FlorianRappl" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, or here for more to come.&lt;/p&gt;

&lt;p&gt;🙏 Thanks to all the authors and contributors for their hard work!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>node</category>
    </item>
    <item>
      <title>Hyper-Scale Activated! Ship Your Own FaaS 🤖</title>
      <dc:creator>Florian Rappl</dc:creator>
      <pubDate>Fri, 18 Oct 2024 12:34:36 +0000</pubDate>
      <link>https://forem.com/smapiot/hyper-scale-activated-ship-your-own-faas-40kg</link>
      <guid>https://forem.com/smapiot/hyper-scale-activated-ship-your-own-faas-40kg</guid>
      <description>&lt;p&gt;In the past decade I've done a lot of work on distributed web applications. In that area you definitely require processes that work implicitly - fully decoupled, with autonomy for individual teams and modules.&lt;/p&gt;

&lt;p&gt;The key question quite often is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How awesome would it be to just extend your application at runtime without any downtime whatsoever?!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this article I want to look at how we can extend a Node server using Express.js to act like a FaaS provider (such as AWS Lambda or Azure Functions).&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To follow this article you'll need the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node.js with npm installed (I recommend version 22 or higher - we'll use &lt;code&gt;fetch&lt;/code&gt; in Node, which is available since version 18)&lt;/li&gt;
&lt;li&gt;A code editor&lt;/li&gt;
&lt;li&gt;If you want to &lt;a href="https://github.com/piral-samples/piral-cloud-express-plugins-demo" rel="noopener noreferrer"&gt;clone the sample project&lt;/a&gt; you'll need to have &lt;code&gt;git&lt;/code&gt; installed (but you can download it as a ZIP from GitHub)&lt;/li&gt;
&lt;li&gt;Access to the &lt;a href="https://feed.piral.cloud" rel="noopener noreferrer"&gt;Piral Cloud Feed Service&lt;/a&gt; - you can use it for free using a Microsoft or GitHub account&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;Before we start to write some code let's look at the anticipated architecture:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0owb6x5e1y9myj26v93m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0owb6x5e1y9myj26v93m.png" alt="Architecture diagram" width="491" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using the &lt;a href="https://feed.piral.cloud" rel="noopener noreferrer"&gt;Piral Cloud Feed Service&lt;/a&gt; we get access to a dynamic service / module registry, which we can leverage to load a list of modules, evaluate them directly from their URLs, and then use them to populate a list of (sub-)routers.&lt;/p&gt;

&lt;p&gt;The routers are necessary to extend the default router middleware. Let's see the whole thing in action. We start by writing the server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing the Server
&lt;/h2&gt;

&lt;p&gt;As server we use a pretty standard and lightweight Express.js server. It can be created by running the following commands in a new directory.&lt;/p&gt;

&lt;p&gt;We first initialize a new npm project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we install the required dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i express
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We add a new file (&lt;em&gt;index.js&lt;/em&gt;) with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello world!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Running at http://localhost:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we finally run the application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go to localhost:3000 in the browser of your choice and see that everything is running as it should:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0e0q1t8rgqiqqm27lzdm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0e0q1t8rgqiqqm27lzdm.png" alt="Server running" width="800" height="522"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great! But there is a bit more to it for making it truly dynamic...&lt;/p&gt;

&lt;h2&gt;
  
  
  Making the Server Dynamic
&lt;/h2&gt;

&lt;p&gt;So what we are after is to run modules that we can just publish whenever we feel the need for it. The first thing to look for is to avoid having routing issues.&lt;/p&gt;

&lt;p&gt;To prevent different modules for occupying the same route we will actually namespace the routes by their module names. In Express.js this also allows us to use dynamic &lt;code&gt;Router&lt;/code&gt; objects, which are bound to their module names.&lt;/p&gt;

&lt;p&gt;In code this can be done like that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/:namespace&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;namespace&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;routers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;router&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We introduce a middleware that is sensitive to a &lt;code&gt;namespace&lt;/code&gt; parameter. In a productive setup we might want to constraint this a bit further, e.g., &lt;code&gt;/api/:namespace&lt;/code&gt; or &lt;code&gt;/apps/:namespace&lt;/code&gt;, to avoid clashes between in-built functionality and the modules.&lt;/p&gt;

&lt;p&gt;The job of the middleware is to use the retrieved &lt;code&gt;namespace&lt;/code&gt; value by looking at all available sub-routers. If a sub-router is matched we will use the sub-router as follow-up middleware. Otherwise, we continue with the next middleware. Usually, the next middleware would be the "not-found-route" from Express.js.&lt;/p&gt;

&lt;p&gt;The question to answer now is how to populate the &lt;code&gt;routers&lt;/code&gt; object. How can we obtain these sub-routers?&lt;/p&gt;

&lt;p&gt;What we can do is to introduce a function to obtain the information from a discovery service. This service gets us all the relevant pieces of information - we then only need to load / run the referenced modules.&lt;/p&gt;

&lt;p&gt;The necessary code to built something like that is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;feed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://feed.piral.cloud/api/v1/pilet/express-demo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;makeId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;@&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;loadPlugins&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Loading plugins ...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;makeId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Integrating plugin "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" ...`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;installPlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Integrated plugin "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"!`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;watchPlugins&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;loadPlugins&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What are we doing here?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We want to start loading the plugins / sub-routers as fast as possible. So we immediately run the &lt;code&gt;loadPlugins&lt;/code&gt; function. Ideally we use the top-level &lt;code&gt;await&lt;/code&gt; here; if it's not available (or if we want to save a bit of startup time) we just call it as shown.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;loadPlugins&lt;/code&gt; fetches the information from the discovery service.&lt;/li&gt;
&lt;li&gt;Once the information is fetched we go over the contained &lt;code&gt;items&lt;/code&gt; array. Each item is treated like the meta information of a plugin - so we just call &lt;code&gt;installPlugin&lt;/code&gt; to use the found meta information.&lt;/li&gt;
&lt;li&gt;Finally we also want to react when something changes - so the &lt;code&gt;loadPlugins&lt;/code&gt; part concludes by watching for changes using the &lt;code&gt;watchPlugins&lt;/code&gt; function.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
  Important Note
  &lt;br&gt;
If you want to follow this on your own then replace &lt;code&gt;https://feed.piral.cloud/api/v1/pilet/express-demo&lt;/code&gt; with your own discovery feed URL. Using the &lt;a href=""&gt;Piral Cloud Feed Service&lt;/a&gt; you can see the URL on the feed overview page.

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6s2r9k06ml4lkuibnndt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6s2r9k06ml4lkuibnndt.png" alt="Finding the Feed Service URL in the feed overview" width="800" height="397"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Let's look at the &lt;code&gt;installPlugin&lt;/code&gt; first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;installPlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;link&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;setup&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;loadModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;setup&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;routers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;makeId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Doesn't look too complicated, does it? What's happening here?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We decompose the item - but we are only interested in the &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;link&lt;/code&gt; (module reference / URL) of the module.&lt;/li&gt;
&lt;li&gt;We create a new Express.js &lt;code&gt;Router&lt;/code&gt; instance (the "sub-router").&lt;/li&gt;
&lt;li&gt;We load the respective module - it should get us a function called &lt;code&gt;setup&lt;/code&gt; (now this is a design choice; you could either name it differently, make it a &lt;code&gt;default&lt;/code&gt; export, or export a &lt;code&gt;Router&lt;/code&gt; instance directly...&lt;/li&gt;
&lt;li&gt;If we really obtained a &lt;code&gt;setup&lt;/code&gt; function we call it with the &lt;code&gt;Router&lt;/code&gt; instance. This can now be modified properly.&lt;/li&gt;
&lt;li&gt;Finally, the created router is assigned to the &lt;code&gt;routers&lt;/code&gt; object and the &lt;code&gt;current&lt;/code&gt; array is extended with the proper entry.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As you might have guessed the &lt;code&gt;current&lt;/code&gt; array is for book-keeping purposes. It allows us to easily patch / change the routers in case of changes. For this, we'll need to look at the &lt;code&gt;watchPlugins&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;WebSocket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ws&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;changeEventTypes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;add-pilet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;update-pilet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;remove-pilet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;watchPlugins&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Watching plugins ...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ws&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;changeEventTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;removeItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;makeId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;addItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nf"&gt;makeId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;removeItems&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;uninstallPlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;addItems&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;installPlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this code to run we rely on the &lt;code&gt;ws&lt;/code&gt; library. So we'll need to install it first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i ws
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;ws&lt;/code&gt; active we can have a look at what the code does:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We define some events we want to listen to. The provided events are send via the WebSocket channel in case the contained modules change.&lt;/li&gt;
&lt;li&gt;Once a message is received we transform it (from raw bytes to a JSON object) and check if the type matches one of the events defined in (1).&lt;/li&gt;
&lt;li&gt;We could now use the information from the event, but some events (e.g., &lt;code&gt;update-pilet&lt;/code&gt;) don't tell us what changed. In such cases we could be in a problematic zone. So we follow the safe route and just re-load all the modules.&lt;/li&gt;
&lt;li&gt;Finally, we need to compare the &lt;em&gt;current&lt;/em&gt; information from the discovery service vs the stored / previous information. For the changed (removed, updated) modules we remove them using the &lt;code&gt;uninstallPlugin&lt;/code&gt;. All the ones that are not yet instantiated we add them using the &lt;code&gt;installPlugin&lt;/code&gt; function.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code&gt;uninstallPlugin&lt;/code&gt; looks as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;uninstallPlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="nx"&gt;routers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That was easy, right? But so far we avoided the most complicated topic. How are we evaluating those modules?&lt;/p&gt;

&lt;h2&gt;
  
  
  Evaluating Modules from URLs
&lt;/h2&gt;

&lt;p&gt;In the browser you can always evaluate ESMs - they are coming from an URL by default. The same is true in runtimes such as Deno. But in Node.js this is not possible. So should we give up?&lt;/p&gt;

&lt;p&gt;As it turns out evaluating URLs is actually not so difficult. We need 2 things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Code to use the &lt;code&gt;vm&lt;/code&gt; module. We need to rely on the &lt;code&gt;SourceTextModule&lt;/code&gt; to create modules on the fly.&lt;/li&gt;
&lt;li&gt;The experimental flag &lt;code&gt;--experimental-vm-modules&lt;/code&gt; for running Node. This way, the &lt;code&gt;SourceTextModule&lt;/code&gt; is available at runtime.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Using those two ways we can add the following code to our server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;linkModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SourceTextModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;link&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;specifier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;specifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;linkModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;loadModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;linkModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Failed to evaluate "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;":`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we have everything together and can just run the server with the flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;--experimental-vm-modules&lt;/span&gt; index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We should see output like this in the console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Loading plugins ...
Running at http://localhost:3000
Integrating plugin "app1@2.0.0" ...
Integrated plugin "app1@2.0.0"!
Integrating plugin "app2@1.0.4" ...
(node:23052) ExperimentalWarning: VM Modules is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
Integrated plugin "app2@1.0.4"!
Integrating plugin "app3@1.0.0" ...
Integrated plugin "app3@1.0.0"!
Watching plugins ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we are already including a couple of modules (referred to as plugins). Let's see what we can do here - how we can write, deploy, and update them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example Functions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  One Module
&lt;/h3&gt;

&lt;p&gt;The first example is a really simple one; just a single function to return a constant string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/foo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello from app1 v2: /foo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Importantly, we initialize a new project and define the &lt;em&gt;package.json&lt;/em&gt; like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"app1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"deploy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"publish-microfrontend --url https://feed.piral.cloud/api/v1/pilet/express-demo --interactive"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"publish-microfrontend"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^1.6.2"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;publish-microfrontend&lt;/code&gt; script is used to deploy the module. This little script just packages the current project and invokes a POST against the provided discovery service URL. The &lt;code&gt;--interactive&lt;/code&gt; flag then allows us to dynamically log into the discovery service to deploy our function.&lt;/p&gt;

&lt;p&gt;We'll see how this process looks in a second. Let's look at another example.&lt;/p&gt;

&lt;h3&gt;
  
  
  Two Modules
&lt;/h3&gt;

&lt;p&gt;While publishing the package with a single module works as expected the question is: Does it also work with more modules? The answer is yes.&lt;/p&gt;

&lt;p&gt;Pretty much the same definition in the &lt;em&gt;package.json&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"app2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"lib/index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"deploy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"publish-microfrontend --url https://feed.dev.piral.cloud/api/v1/pilet/express-demo --interactive"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"publish-microfrontend"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^1.6.2"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But now &lt;em&gt;lib/index.js&lt;/em&gt; is different:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;compute&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./other.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/compute&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;compute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isNaN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Only numbers allowed.`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not only is this a bit more logic - it also uses a function from another module located at &lt;em&gt;lib/other.js&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;compute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you might have guessed our ESM URL loader just works as it should. No questions asked. Great!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhhs1gkr4elzp5ovt855h.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhhs1gkr4elzp5ovt855h.gif" alt="Impressive" width="500" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We won't answer the burning question: Can it do three modules? I guess we know the answer, but if you want to find out get active now!&lt;/p&gt;

&lt;p&gt;In the meantime we go already to the complex case of having the modules written in TypeScript - and including some dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  TypeScript Modules with Dependencies
&lt;/h3&gt;

&lt;p&gt;Consider the code at &lt;em&gt;src/index.ts&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cors&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express-serve-static-core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cors&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

  &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`NOT FOUND.`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we are using types and dependencies. This won't work - we don't do any dependency resolution and we don't transpile TypeScript. So should we be worried? Not at all!&lt;/p&gt;

&lt;p&gt;Let's bundle it using esbuild:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;esbuild &lt;span class="nt"&gt;--outdir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dist src/index.ts &lt;span class="nt"&gt;--bundle&lt;/span&gt; &lt;span class="nt"&gt;--platform&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;node &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;esm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even better - we can just extend the &lt;em&gt;package.json&lt;/em&gt; to take care of this in the &lt;code&gt;deploy&lt;/code&gt; task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"app3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dist/index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"esbuild --outdir=dist src/index.ts --bundle --platform=node --format=esm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"deploy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm run build &amp;amp;&amp;amp; publish-microfrontend --url https://feed.dev.piral.cloud/api/v1/pilet/express-demo --interactive"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@types/cors"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^2.8.17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@types/express"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^5.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"esbuild"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^0.24.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"publish-microfrontend"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^1.6.2"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cors"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^2.8.5"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, we can just write anything - bundle it using &lt;code&gt;esbuild&lt;/code&gt; and ship it with &lt;code&gt;publish-microfrontend&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now let's step back a bit and see how we actually deploy the modules:&lt;/p&gt;

&lt;h3&gt;
  
  
  Deployment
&lt;/h3&gt;

&lt;p&gt;Maybe let's see first how it looks in the discovery service when we deployed all of our modules:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1c541s2pz9etr7v8qwt8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1c541s2pz9etr7v8qwt8.png" alt="Overview of modules" width="800" height="209"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As already mentioned for deploying such a module we can use the available &lt;code&gt;publish-microfrontend&lt;/code&gt; npm package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx publish-microfrontend &lt;span class="nt"&gt;--url&lt;/span&gt; &amp;lt;your-discovery-service-url&amp;gt; &lt;span class="nt"&gt;--api-key&lt;/span&gt; &amp;lt;your-key&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In cases such as the ones above we might swap the &lt;code&gt;--api-key&lt;/code&gt; with an &lt;code&gt;--interactive&lt;/code&gt; flow, where we need to use the browser for obtaining a user token instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx publish-microfrontend &lt;span class="nt"&gt;--url&lt;/span&gt; &amp;lt;your-discovery-service-url&amp;gt; &lt;span class="nt"&gt;--interactive&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's see how this process looks in real life:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8p39e4ejphb5ysrznaco.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8p39e4ejphb5ysrznaco.gif" alt="The publish process in motion" width="800" height="604"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the end having such a powerful service registry between our server and the respective modules is not only clean, but also useful for flexibility reasons.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced Dynamics
&lt;/h2&gt;

&lt;p&gt;We already saw that the dynamics with respect to partial rollbacks are in place from the beginning. In general, the service registry's portal gives us the ability to control every bit of the delivery process:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxxobl0sbqeqblhbjdww5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxxobl0sbqeqblhbjdww5.png" alt="Version selector" width="800" height="207"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The version selector in particular is quite useful. Besides the possibility of making rollbacks, we can also do feature flags, A/B testing, blue-green deployments, or canary releases.&lt;/p&gt;

&lt;p&gt;Quite powerful stuff...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5y45mlet4a9ut9phpmgq.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5y45mlet4a9ut9phpmgq.gif" alt="Homelander" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This allows us, e.g., to have multiple instances of our Express.js server, where each instance might get a different set of modules. Sounds crazy (how can this be useful?!) but if you don't consider these instances equal (i.e., meant for scaling), but rather as different sites (e.g., one for US, one for EU etc.) then backend behavior might be different - at least in some areas.&lt;/p&gt;

&lt;p&gt;Beforehand, that was a lot of overhead. You had to produce countless variations of the same server - now you can just have one and have the different behavior qualified through the loaded modules.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article you've seen how you can easily extend your Express.js server into a FaaS platform allowing you to add, update, and remove endpoints on the fly.&lt;/p&gt;

&lt;p&gt;Of course, the provided sample is rather simplistic and does not solve some of the issues including advanced isolation, memory footprint (unload and restrictions of modules), local module development using an emulator, and many others. But it's a very convenient start - showing what's possible with just a few lines of code.&lt;/p&gt;

&lt;p&gt;Check out the sample code at &lt;a href="https://github.com/piral-samples/piral-cloud-express-plugins-demo" rel="noopener noreferrer"&gt;github.com/piral-samples/piral-cloud-express-plugins-demo&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>node</category>
      <category>express</category>
    </item>
    <item>
      <title>🎃 50 Articles to Avoid Web Dev Nightmares</title>
      <dc:creator>Florian Rappl</dc:creator>
      <pubDate>Tue, 15 Oct 2024 13:28:34 +0000</pubDate>
      <link>https://forem.com/florianrappl/50-articles-to-web-dev-nightmares-15ah</link>
      <guid>https://forem.com/florianrappl/50-articles-to-web-dev-nightmares-15ah</guid>
      <description>&lt;p&gt;This year I started a new series on &lt;a href="https://www.linkedin.com/in/florian-rappl/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; - "Advanced Links for Frontend". Each issue has 10 links to outstanding posts / articles. This bundle contains the links from the last 5 issues (issue 56 to issue 60).&lt;/p&gt;

&lt;p&gt;I hope you enjoy this collection. Let me know in the comments which of these articles is your favorite (and why).&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 56
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The CSS radial composer&lt;/strong&gt; (&lt;a href="https://zumerlab.github.io/orbit-docs/" rel="noopener noreferrer"&gt;https://zumerlab.github.io/orbit-docs/&lt;/a&gt;) by Orbit&lt;br&gt;
Gravity is everywhere! For some reason I feel attracted to this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remix's concurrent submissions are fundamentally flawed&lt;/strong&gt; (without causal ordering) (&lt;a href="https://dashbit.co/blog/remix-concurrent-submissions-flawed" rel="noopener noreferrer"&gt;https://dashbit.co/blog/remix-concurrent-submissions-flawed&lt;/a&gt;) by José Valim&lt;br&gt;
Honestly, I am not surprised.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ts-blank-space&lt;/strong&gt; (&lt;a href="https://bloomberg.github.io/ts-blank-space/" rel="noopener noreferrer"&gt;https://bloomberg.github.io/ts-blank-space/&lt;/a&gt;) by Ashley Claymore&lt;br&gt;
This can be really useful, but I wonder why not just esbuild is used. It's fast and can also be used for more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;date-fns v4.0 is out with first-class time zones support!&lt;/strong&gt; (&lt;a href="https://blog.date-fns.org/v40-with-time-zone-support/" rel="noopener noreferrer"&gt;https://blog.date-fns.org/v40-with-time-zone-support/&lt;/a&gt;) by Sasha Koss&lt;br&gt;
Well, having time zones support is one of the things I'd consider necessary for any good time library.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fastify v5 is Now Officially Released!&lt;/strong&gt; (&lt;a href="https://openjsf.org/blog/fastifys-growth-and-success" rel="noopener noreferrer"&gt;https://openjsf.org/blog/fastifys-growth-and-success&lt;/a&gt;) by Fastify Team&lt;br&gt;
Fastify is great and presumably under-appreciated in the Node.js community.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WebKit Features in Safari 18.0&lt;/strong&gt; (&lt;a href="https://webkit.org/blog/15865/webkit-features-in-safari-18-0/" rel="noopener noreferrer"&gt;https://webkit.org/blog/15865/webkit-features-in-safari-18-0/&lt;/a&gt;) by Jen Simmons&lt;br&gt;
Keep an eye on this - view transitions and WebXR are huge! Fantastic release!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Biome v1.9 Anniversary Release&lt;/strong&gt; (&lt;a href="https://biomejs.dev/blog/biome-v1-9/" rel="noopener noreferrer"&gt;https://biomejs.dev/blog/biome-v1-9/&lt;/a&gt;) by Victorien Elvinger&lt;br&gt;
Alright I can happily say that finally Biome is also becoming interesting to me. Goodbye Prettier + eslint!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A milestone for TypeScript Performance in TanStack Router&lt;/strong&gt; (&lt;a href="https://tanstack.com/blog/tanstack-router-typescript-performance" rel="noopener noreferrer"&gt;https://tanstack.com/blog/tanstack-router-typescript-performance&lt;/a&gt;) by Christopher Horobin&lt;br&gt;
Great write-up with some insights on how the type checker / TypeScript performance can be evaluated and improved.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;New Values and Functions in CSS&lt;/strong&gt; (&lt;a href="https://dev.to/alvaromontoro/new-values-and-functions-in-css-1b9o"&gt;https://dev.to/alvaromontoro/new-values-and-functions-in-css-1b9o&lt;/a&gt;) by &lt;a class="mentioned-user" href="https://dev.to/alvaromontoro"&gt;@alvaromontoro&lt;/a&gt; &lt;br&gt;
Well, some of these functions are not really new, but it's always good to be reminded about them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deno 2.0 Release Candidate&lt;/strong&gt; (&lt;a href="https://deno.com/blog/v2.0-release-candidate" rel="noopener noreferrer"&gt;https://deno.com/blog/v2.0-release-candidate&lt;/a&gt;) by Andy Jiang and Bartek Iwańczuk&lt;br&gt;
The v2 promises to be a really well-rounded release. Time for everyone to take another look at Deno!&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 57
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;How Discord Reduced Websocket Traffic by 40%&lt;/strong&gt; (&lt;a href="https://discord.com/blog/how-discord-reduced-websocket-traffic-by-40-percent" rel="noopener noreferrer"&gt;https://discord.com/blog/how-discord-reduced-websocket-traffic-by-40-percent&lt;/a&gt;) by Austin Whyte&lt;br&gt;
A lot of micro optimizations and lazy loading (or "sending") for the win!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You Can't Build Interactive Web Apps Except as Single Page Applications... And Other Myths&lt;/strong&gt; (&lt;a href="https://htmx.org/essays/you-cant/" rel="noopener noreferrer"&gt;https://htmx.org/essays/you-cant/&lt;/a&gt;) by Tony Alaribe&lt;br&gt;
Never heard that myth - but it's fine for me to claim that fire has been rediscovered.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Component Composition is great btw&lt;/strong&gt; (&lt;a href="https://tkdodo.eu/blog/component-composition-is-great-btw" rel="noopener noreferrer"&gt;https://tkdodo.eu/blog/component-composition-is-great-btw&lt;/a&gt;) by Dominik Dorfmeister&lt;br&gt;
Truly. What's also great is to have the right company boundaries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compile and run C in JavaScript&lt;/strong&gt; (&lt;a href="https://bun.sh/blog/compile-and-run-c-in-js" rel="noopener noreferrer"&gt;https://bun.sh/blog/compile-and-run-c-in-js&lt;/a&gt;) by Jarred Sumner&lt;br&gt;
More like: Compile and run C in Bun. As usual, I see the devil being in the detail.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Nine Node Pillars&lt;/strong&gt; (&lt;a href="https://www.platformatichq.com/node-principles" rel="noopener noreferrer"&gt;https://www.platformatichq.com/node-principles&lt;/a&gt;) by Matteo Collina et al.&lt;br&gt;
It's great to recap those pillars, even though I did not find anything really Node.js specific (most of the points could be assigned on to any web server).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Module Federation Vite the new v1 is here 🎉&lt;/strong&gt; (&lt;a href="https://www.learnbydo.ing/diary/2024-09-23-module-federation-vite-v1" rel="noopener noreferrer"&gt;https://www.learnbydo.ing/diary/2024-09-23-module-federation-vite-v1&lt;/a&gt;) by Giorgio Boa&lt;br&gt;
Happy to see that progress is made! Now we only miss all the other bundlers ...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Golden Ratio in CSS&lt;/strong&gt; (&lt;a href="https://dev.to/madsstoumann/the-golden-ratio-in-css-53d0"&gt;https://dev.to/madsstoumann/the-golden-ratio-in-css-53d0&lt;/a&gt;) by &lt;a class="mentioned-user" href="https://dev.to/madsstoumann"&gt;@madsstoumann&lt;/a&gt; &lt;br&gt;
Sweet - starts with some boxes and ends with a lot of rings. I love it!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sticky Transitioning Veggie Hamburger 🍔&lt;/strong&gt; (&lt;a href="https://dev.to/florianrappl/sticky-transitioning-veggie-hamburger-7dd"&gt;https://dev.to/florianrappl/sticky-transitioning-veggie-hamburger-7dd&lt;/a&gt;) by &lt;a class="mentioned-user" href="https://dev.to/florianrappl"&gt;@florianrappl&lt;/a&gt; &lt;br&gt;
Put your web app on a diet and reduce the amount of JS - especially when not needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Typed Linting Needs TypeScript Today&lt;/strong&gt; (&lt;a href="https://www.joshuakgoldberg.com/blog/why-typed-linting-needs-typescript-today/" rel="noopener noreferrer"&gt;https://www.joshuakgoldberg.com/blog/why-typed-linting-needs-typescript-today/&lt;/a&gt;) by Josh Goldberg&lt;br&gt;
Every once in a while somebody tries to reimplement TypeScript - so far everyone failed. Yes, TypeScript is required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Improving rendering performance with CSS content-visibility&lt;/strong&gt; (&lt;a href="https://nolanlawson.com/2024/09/18/improving-rendering-performance-with-css-content-visibility/" rel="noopener noreferrer"&gt;https://nolanlawson.com/2024/09/18/improving-rendering-performance-with-css-content-visibility/&lt;/a&gt;) by Nolan Lawson&lt;br&gt;
This is indeed magical. I see some difficulties here, but certainly no less than doing actual lazy loading / virtualization in JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 58
&lt;/h2&gt;

&lt;p&gt;Ever faced the problem of dead space through gaps using flexbox or grid? Then read about&lt;br&gt;
&lt;strong&gt;Sanding UI&lt;/strong&gt; (&lt;a href="https://blog.jim-nielsen.com/2024/sanding-ui/" rel="noopener noreferrer"&gt;https://blog.jim-nielsen.com/2024/sanding-ui/&lt;/a&gt;) by Jim Nielsen&lt;/p&gt;

&lt;p&gt;As you are all aware Ahmad has become my favorite author for CSS related articles. Recently he gave his website some polish. Read about the&lt;br&gt;
&lt;strong&gt;Redesign Case Study&lt;/strong&gt; (&lt;a href="https://ishadeed.com/article/redesign-2024/" rel="noopener noreferrer"&gt;https://ishadeed.com/article/redesign-2024/&lt;/a&gt;) by Ahmad Shadeed&lt;/p&gt;

&lt;p&gt;Now that we conquered client islands it's time for server islands to become standard. One way is discussed in&lt;br&gt;
&lt;strong&gt;Partial Prerendering for Everyone with Cloudflare Workers&lt;/strong&gt; (&lt;a href="https://sunilpai.dev/posts/ppr-for-everyone/" rel="noopener noreferrer"&gt;https://sunilpai.dev/posts/ppr-for-everyone/&lt;/a&gt;) by Sunil Pai&lt;/p&gt;

&lt;p&gt;It was quite a week for web components. We started with&lt;br&gt;
&lt;strong&gt;Web Components Are Not the Future&lt;/strong&gt; (&lt;a href="https://dev.to/ryansolid/web-components-are-not-the-future-48bh"&gt;https://dev.to/ryansolid/web-components-are-not-the-future-48bh&lt;/a&gt;) by &lt;a class="mentioned-user" href="https://dev.to/ryansolid"&gt;@ryansolid&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;But as usual on this topic there had to be different opinions. Entering&lt;br&gt;
&lt;strong&gt;Web Components Are Not the Future — They’re the Present&lt;/strong&gt; (&lt;a href="https://www.abeautifulsite.net/posts/web-components-are-not-the-future-they-re-the-present/" rel="noopener noreferrer"&gt;https://www.abeautifulsite.net/posts/web-components-are-not-the-future-they-re-the-present/&lt;/a&gt;) by Cory LaViska&lt;/p&gt;

&lt;p&gt;In the end both have their points and perspectives, but like the old XKCD comic it was the job of a third person to summarize in&lt;br&gt;
&lt;strong&gt;Web components are okay&lt;/strong&gt; (&lt;a href="https://nolanlawson.com/2024/09/28/web-components-are-okay/" rel="noopener noreferrer"&gt;https://nolanlawson.com/2024/09/28/web-components-are-okay/&lt;/a&gt;) by Nolan Lawson&lt;/p&gt;

&lt;p&gt;Years ago we tried to introduce scoping in CSS - but without much success. Now the working group is back with power... Let's try&lt;br&gt;
&lt;strong&gt;Understanding the Concept of Scoping in CSS&lt;/strong&gt; (&lt;a href="https://dev.to/bilkeesu96/understanding-the-concept-of-scoping-in-css-1m9g"&gt;https://dev.to/bilkeesu96/understanding-the-concept-of-scoping-in-css-1m9g&lt;/a&gt;) by &lt;a class="mentioned-user" href="https://dev.to/bilkeesu96"&gt;@bilkeesu96&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;A major downside of classic cron jobs is the failure cascade. This can be countered by some worker frameworks - for instance offering something dubbed durable functions.&lt;br&gt;
&lt;strong&gt;What are Durable Functions? A visual JavaScript primer&lt;/strong&gt; (&lt;a href="https://www.inngest.com/blog/durable-functions-a-visual-javascript-primer" rel="noopener noreferrer"&gt;https://www.inngest.com/blog/durable-functions-a-visual-javascript-primer&lt;/a&gt;) by Lydia Hallie&lt;/p&gt;

&lt;p&gt;Having tests is both - a pain and necessity. Especially in the frontend things tend to become difficult - relying on the browser and user behavior for many features. Let's recap&lt;br&gt;
&lt;strong&gt;Testing Frontend — Lessons from over a million lines of TypeScript at Palantir&lt;/strong&gt; (&lt;a href="https://www.meticulous.ai/blog/lessons-from-a-decade" rel="noopener noreferrer"&gt;https://www.meticulous.ai/blog/lessons-from-a-decade&lt;/a&gt;) by Quentin Spencer-Harper&lt;/p&gt;

&lt;p&gt;Not only the web component department delivered... If you missed the excitement delivered by the WordPress community then read&lt;br&gt;
&lt;strong&gt;The messy WordPress drama, explained&lt;/strong&gt; (&lt;a href="https://www.theverge.com/2024/9/27/24256361/wordpress-wp-engine-drama-explained-matt-mullenweg" rel="noopener noreferrer"&gt;https://www.theverge.com/2024/9/27/24256361/wordpress-wp-engine-drama-explained-matt-mullenweg&lt;/a&gt;) by Emma Roth&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 59
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Building a Single-Page App with htmx&lt;/strong&gt; (&lt;a href="https://jakelazaroff.com/words/building-a-single-page-app-with-htmx/" rel="noopener noreferrer"&gt;https://jakelazaroff.com/words/building-a-single-page-app-with-htmx/&lt;/a&gt;) by Jake Lazaroff&lt;br&gt;
Your scientists were so preoccupied with whether or not they could, they didn't stop to think if they should.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keeping an eye on changes to MDN’s Browser Compatibility Data&lt;/strong&gt; (&lt;a href="https://bcd-watch.igalia.com/" rel="noopener noreferrer"&gt;https://bcd-watch.igalia.com/&lt;/a&gt;) by igalia&lt;br&gt;
This is quite neat - not only knowing what changed, but also when it changed.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;OpenFreeMap *&lt;/em&gt;(&lt;a href="https://openfreemap.org/" rel="noopener noreferrer"&gt;https://openfreemap.org/&lt;/a&gt;) by Zsolt Ero&lt;br&gt;
Eagerly waiting to use this with Leaflet - but the Mapbox demos look great, too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bridging the hard and the soft&lt;/strong&gt; (&lt;a href="https://wattenberger.com/thoughts/hard-and-soft" rel="noopener noreferrer"&gt;https://wattenberger.com/thoughts/hard-and-soft&lt;/a&gt;) by Amelia Wattenberger&lt;br&gt;
Superb read - it's all about the interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ESLint now officially supports linting of JSON and Markdown&lt;/strong&gt; (&lt;a href="https://eslint.org/blog/2024/10/eslint-json-markdown-support/" rel="noopener noreferrer"&gt;https://eslint.org/blog/2024/10/eslint-json-markdown-support/&lt;/a&gt;) by Nicholas Zakas&lt;br&gt;
I am not getting enough warnings already.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tauri 2.0 Stable Release&lt;/strong&gt; (&lt;a href="https://v2.tauri.app/blog/tauri-20/" rel="noopener noreferrer"&gt;https://v2.tauri.app/blog/tauri-20/&lt;/a&gt;) by Tillmann Weidinger&lt;br&gt;
It's now just a much better DX.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Running Clang in the browser using WebAssembly&lt;/strong&gt; (&lt;a href="https://wasmer.io/posts/clang-in-browser" rel="noopener noreferrer"&gt;https://wasmer.io/posts/clang-in-browser&lt;/a&gt;) by Syrus Akbary&lt;br&gt;
I need to repeat: Your scientists were so preoccupied with whether or not they could, they didn't stop to think if they should.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unleash JavaScript's Potential with Functional Programming&lt;/strong&gt; (&lt;a href="https://janhesters.com/blog/unleash-javascripts-potential-with-functional-programming" rel="noopener noreferrer"&gt;https://janhesters.com/blog/unleash-javascripts-potential-with-functional-programming&lt;/a&gt;) by Jan Hesters&lt;br&gt;
Personal opinion: Don't get too much into FP, but just take the best pieces and use them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Local-First Case Study&lt;/strong&gt; (&lt;a href="https://jakelazaroff.com/words/a-local-first-case-study/" rel="noopener noreferrer"&gt;https://jakelazaroff.com/words/a-local-first-case-study/&lt;/a&gt;) by Jake Lazaroff&lt;br&gt;
Local-first is underappreciated but should be a cornerstone for good DX.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Gumroad Didn't Choose htmx&lt;/strong&gt; (&lt;a href="https://htmx.org/essays/why-gumroad-didnt-choose-htmx/" rel="noopener noreferrer"&gt;https://htmx.org/essays/why-gumroad-didnt-choose-htmx/&lt;/a&gt;) by Sahil Lavingia&lt;br&gt;
It's fine. No one needs to choose everything. Everything has trade-offs and I believe in choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 60
&lt;/h2&gt;

&lt;p&gt;If you look for icons to be used in your next project - then maybe start directly at&lt;br&gt;
&lt;strong&gt;15+ Best Icon Libraries of 2024&lt;/strong&gt; (&lt;a href="https://dev.to/vinishbhaskar/best-icon-libraries-28ce"&gt;https://dev.to/vinishbhaskar/best-icon-libraries-28ce&lt;/a&gt;) by &lt;a class="mentioned-user" href="https://dev.to/vinishbhaskar"&gt;@vinishbhaskar&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Ever wondered how to get or set up a great CRM for free? if so, check out&lt;br&gt;
&lt;strong&gt;Atomic CRM&lt;/strong&gt; (&lt;a href="https://marmelab.com/atomic-crm/" rel="noopener noreferrer"&gt;https://marmelab.com/atomic-crm/&lt;/a&gt;) by Marmelab&lt;/p&gt;

&lt;p&gt;In case you missed the preview you can now enjoy the full next gen Node.js competitor;&lt;br&gt;
&lt;strong&gt;Announcing Deno 2&lt;/strong&gt; (&lt;a href="https://deno.com/blog/v2.0" rel="noopener noreferrer"&gt;https://deno.com/blog/v2.0&lt;/a&gt;) by Ryan Dahl&lt;/p&gt;

&lt;p&gt;Are you sometimes hesitant to just install npm packages? Paranoid, maybe not - here are some&lt;br&gt;
&lt;strong&gt;Nightmares on npm: How Two Malicious Packages Facilitate Data Theft and Destruction&lt;/strong&gt; (&lt;a href="https://socket.dev/blog/nightmares-on-npm-how-two-malicious-packages-facilitate-data-theft-and-destruction" rel="noopener noreferrer"&gt;https://socket.dev/blog/nightmares-on-npm-how-two-malicious-packages-facilitate-data-theft-and-destruction&lt;/a&gt;) by Kush Pandya&lt;/p&gt;

&lt;p&gt;I think there is a great new framework in town (no week without it!) - server-first with JSX to web components for islands of interactivity. Entering&lt;br&gt;
&lt;strong&gt;The Web Platform Framework&lt;/strong&gt; (&lt;a href="https://brisa.build" rel="noopener noreferrer"&gt;https://brisa.build&lt;/a&gt;) by Aral Roca Gomez&lt;/p&gt;

&lt;p&gt;Ever thought that logs can provide much more insights, but are too clumsy to work with? Maybe strict sequential logs are not the answer. One approach can be found by reading an&lt;br&gt;
&lt;strong&gt;Introduction to Causal Logs&lt;/strong&gt; (&lt;a href="https://joelgustafson.com/posts/2024-09-30/introduction-to-causal-logs" rel="noopener noreferrer"&gt;https://joelgustafson.com/posts/2024-09-30/introduction-to-causal-logs&lt;/a&gt;) by Joel Gustafson&lt;/p&gt;

&lt;p&gt;Besides having a new framework each week there is also another attempt on explaining and visualizing how React renders (or reconciliates) your view - so let's dive into&lt;br&gt;
&lt;strong&gt;The Interactive Guide to Rendering in React&lt;/strong&gt; (&lt;a href="https://ui.dev/why-react-renders" rel="noopener noreferrer"&gt;https://ui.dev/why-react-renders&lt;/a&gt;) by UiDev&lt;/p&gt;

&lt;p&gt;Do you believe that JavaScript on the server is essentially PHP? I did not - but if you did then read&lt;br&gt;
&lt;strong&gt;React on the server is not PHP&lt;/strong&gt; (&lt;a href="https://www.artmann.co/articles/react-on-the-server-is-not-php" rel="noopener noreferrer"&gt;https://www.artmann.co/articles/react-on-the-server-is-not-php&lt;/a&gt;) by Christoffer Artmann&lt;/p&gt;

&lt;p&gt;Do you like mysteries? Then try solving the riddle of&lt;br&gt;
&lt;strong&gt;Node.js, pipes, and disappearing bytes&lt;/strong&gt; (&lt;a href="https://sxlijin.github.io/2024-10-09-node-stdout-disappearing-bytes" rel="noopener noreferrer"&gt;https://sxlijin.github.io/2024-10-09-node-stdout-disappearing-bytes&lt;/a&gt;) by Sam Lijin&lt;/p&gt;

&lt;p&gt;I have a feeling that the server-side story for React gets more fragmented and unnecessarily complex each day - even without talking about&lt;br&gt;
&lt;strong&gt;Serverless servers and the challenge of new React architecture&lt;/strong&gt; (&lt;a href="https://bobaekang.com/blog/serverless-servers-and-the-challenge-of-new-react-architecture/" rel="noopener noreferrer"&gt;https://bobaekang.com/blog/serverless-servers-and-the-challenge-of-new-react-architecture/&lt;/a&gt;) by Bobae Kang&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;These are all outstanding articles by masterful authors. I enjoyed reading them all - I hope you did find something in there, too.&lt;/p&gt;

&lt;p&gt;👉 Follow me on &lt;a href="https://www.linkedin.com/in/florian-rappl/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://twitter.com/FlorianRappl" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, or here for more to come.&lt;/p&gt;

&lt;p&gt;🙏 Thanks to all the authors and contributors for their hard work!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>node</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Sticky Transitioning Veggie Hamburger 🍔</title>
      <dc:creator>Florian Rappl</dc:creator>
      <pubDate>Wed, 25 Sep 2024 08:40:42 +0000</pubDate>
      <link>https://forem.com/florianrappl/sticky-transitioning-veggie-hamburger-7dd</link>
      <guid>https://forem.com/florianrappl/sticky-transitioning-veggie-hamburger-7dd</guid>
      <description>&lt;p&gt;In our efforts to make the page &lt;em&gt;faster&lt;/em&gt; and &lt;strong&gt;even faster&lt;/strong&gt; we also explored different ways of just omitting user interactivity altogether. One place we looked at intensively was the header (or general layout). The header contained a bit of interactivity in form of a React component.&lt;/p&gt;

&lt;p&gt;The job of the header component is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;on mobile show a persistent header bar with a hamburger instead of the normal entries&lt;/li&gt;
&lt;li&gt;on desktop show all the menu entries, but switch the appearance once scrolling occurs (full height to less height with a shadow below)&lt;/li&gt;
&lt;li&gt;the menu on mobile should not have any scrolling (i.e., remove scrollbar if any)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In practice this looks like the following on desktop:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc2qhgrso198o5epq8vxk.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc2qhgrso198o5epq8vxk.gif" alt="Desktop header"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And for mobile the appearance changes to this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5q2z9593csqbuin46tsk.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5q2z9593csqbuin46tsk.gif" alt="Mobile header"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's see how we went from the original to a non-JS version that behaves the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  Original Meat Burger
&lt;/h2&gt;

&lt;p&gt;Alright, we start with the original version of our header (the "hamburger"). To stay rather generic for this article we prepared a small sample that evolves with every step.&lt;/p&gt;

&lt;p&gt;We start with the original:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/vitejs-vite-tpfcpd?embed=1&amp;amp;file=src%2FPageHeader.jsx&amp;amp;view=editor" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Most of the code is in the CSS-in-JS. You don't need to use the CSS-in-JS here (we actually use SASS), but it easily brings the two parts (CSS and React) that are needed for the component together.&lt;/p&gt;

&lt;p&gt;The critical part is that within the component we need to use some hooks (i.e., interactivity) to make it work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PageHeader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setOpen&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useStickyHeader&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nf"&gt;useLockBodyScroll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal is thus to reduce it. Let's start with the easy thing first: How to get the hamburger menu working without JS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Less Meat - Same Taste
&lt;/h2&gt;

&lt;p&gt;How can we toggle two states using CSS and no JS? Well, first we need to understand that CSS inherently allows us to distinguish between states. For instance, CSS allows to select based on&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;empty&lt;/li&gt;
&lt;li&gt;hovered&lt;/li&gt;
&lt;li&gt;focused&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and more states directly. Among those are also special states of some form fields, e.g., if a checkbox is checked.&lt;/p&gt;

&lt;p&gt;So instead of toggling based on a &lt;code&gt;data-&lt;/code&gt; attribute, i.e., the following code in CSS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;header&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-open&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"true"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we can toggle this based on another selector:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;header&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;#header-hamburger-open&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This assumes that a new element with the ID &lt;code&gt;header-hamburger-open&lt;/code&gt; has been introduced. This is a checkbox that is hidden to the user. The effect of hiding the checkbox can be done quite easily using CSS, too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nf"&gt;#header-hamburger-open&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;visibility&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;collapse&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Personally, I like to use &lt;code&gt;visibility: collapse&lt;/code&gt; as it transports the meaning the best. Unfortunately, for most elements Webkit-based/derived browsers will behave for &lt;code&gt;collapse&lt;/code&gt; like for &lt;code&gt;hidden&lt;/code&gt; - i.e., reserving the original space but not rendering the element.&lt;/p&gt;

&lt;p&gt;Only Firefox behaves in a way that aligns with the original meaning (but contrary to the spec - which is actually weird in this scenario). That's why we need the additional &lt;code&gt;height: 0&lt;/code&gt; to also prevent allocating same space on Webkit-based browsers such as Chrome.&lt;/p&gt;

&lt;p&gt;With this in mind we replace the original &lt;code&gt;button&lt;/code&gt; inside the &lt;code&gt;navbar-toggler&lt;/code&gt; with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"header-hamburger-open"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"navbar-toggler"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;
    &lt;span class="na"&gt;htmlFor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"header-hamburger-open"&lt;/span&gt;
    &lt;span class="na"&gt;data-toggle&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"collapse"&lt;/span&gt;
    &lt;span class="na"&gt;aria-controls&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"navbar-menu-content"&lt;/span&gt;
    &lt;span class="na"&gt;aria-label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Toggle navigation"&lt;/span&gt;
  &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    🍔
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When clicking on the &lt;code&gt;label&lt;/code&gt; the &lt;code&gt;htmlFor&lt;/code&gt; attribute is used by the browser. This will lead to toggling the checkbox, which - as per our CSS structure - will toggle the menu.&lt;/p&gt;

&lt;p&gt;You can play around with this in the updated sample.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/vitejs-vite-zdvtvx?embed=1&amp;amp;file=src%2FPageHeader.jsx&amp;amp;view=editor" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Now that the easy part is done - let's look at the final step for making the truly JS-free: Having the sticky positioning fulfilled.&lt;/p&gt;

&lt;h2&gt;
  
  
  Veggie Version - Original Taste
&lt;/h2&gt;

&lt;p&gt;The main complication when moving the sticky header from a JS transition to a CSS one is that CSS has no idea about scrolling.&lt;/p&gt;

&lt;p&gt;Let's see the original hook / code to trigger the transition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useStickyHeader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useLayoutEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sticky&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;offsetTop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onscroll&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pageYOffset&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;sticky&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sticky&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sticky&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onscroll&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So by applying the CSS class &lt;code&gt;sticky&lt;/code&gt; we transform the original header to the sticky one. Without JavaScript - this won't be possible.&lt;/p&gt;

&lt;p&gt;Maybe - so the idea - it is possible to have something set from the beginning. So the idea is to have the right layout and not rely on a scrolling-based transition.&lt;/p&gt;

&lt;p&gt;The starting point should be the CSS declaration &lt;code&gt;position: sticky&lt;/code&gt;. Using &lt;code&gt;position: sticky&lt;/code&gt; we can tell the browser to make the menu sticky (in relation to its scrolling container) without relying on a transition.&lt;/p&gt;

&lt;p&gt;The problem with &lt;code&gt;position: sticky&lt;/code&gt; is that we can only tell the browser what "position" we want to settle in. For instance, we can tell the browser &lt;code&gt;top: -10px&lt;/code&gt; to keep moving the header bar until it's 10 pixels inside the containers hidden area, i.e., shifted to the top by 10px. There is no way to add another shadow or other things we might be interested in...&lt;/p&gt;

&lt;p&gt;This is the point where we could call it a day, marking the task as "impossible" and move on.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu063eb829fa3zkyaeuzz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu063eb829fa3zkyaeuzz.jpg" alt="CSS one does not simply meme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luckily, there are still some tricks we can apply in this case. Let's look at what we want:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiysgn273ll6ey99u3qpp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiysgn273ll6ey99u3qpp.png" alt="Header transition"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In other words, we want to "reveal" part of the shadow when we move up. The moving up part we get covered by using &lt;code&gt;position: sticky&lt;/code&gt; as outlined - now the shadow part could be tricked in by really introducing such layers.&lt;/p&gt;

&lt;p&gt;What we mean specifically is that we could introduce two more "virtual" elements (using &lt;code&gt;::before&lt;/code&gt; and &lt;code&gt;::after&lt;/code&gt; pseudo selectors):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one element moving together with the sticky header (i.e., absolutely positioned) - initially "hiding" the shadow&lt;/li&gt;
&lt;li&gt;one element as a shadow that is being fixed; thus not moving with the sticky header (initially being hidden behind the absolutely positioned element)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that both need to be in the foreground. This means we have a layering such as:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb9d502ownlcsj13xhmv3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb9d502ownlcsj13xhmv3.png" alt="Layering of elements"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The real header (blue) is now shorter, but extended with the overlay element (green), which is initially hiding the shadow (purple). Once the page (red) scrolls, the header scrolls up to a certain point. Together with it the overlay is supposed to scroll, thus revealing the shadow:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fclask9uidhs2colo8kx0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fclask9uidhs2colo8kx0.png" alt="Scrolling of elements"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In theory that should work - but in reality it will all be determined by the specific values we pick for the positioning of these elements.&lt;/p&gt;

&lt;p&gt;In CSS the following is needed to introduce the two virtual elements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="p"&gt;*::&lt;/span&gt;&lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;fixed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;%;&lt;/span&gt;
  &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;45&lt;/span&gt;&lt;span class="n"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;ccc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;box&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="n"&gt;px&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="n"&gt;px&lt;/span&gt; &lt;span class="nf"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;57&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;63&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;72&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;9999&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="p"&gt;*::&lt;/span&gt;&lt;span class="n"&gt;after&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;%;&lt;/span&gt;
  &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;55&lt;/span&gt;&lt;span class="n"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;ccc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;9999&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The header itself is positioned in a way that makes it be in front of these layers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;header&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sticky&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-5px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;z-index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates the effect we are looking for - and without requiring any JavaScript whatsoever.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/vitejs-vite-ukluve?embed=1&amp;amp;file=src%2FPageHeader.jsx&amp;amp;view=editor" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Going to a full non-JS version of our header made the lighthouse score even better - being a full 100 on most / all pages. Now, whenever JS is needed it would be just there to enhance a certain view or give more details. There is no more JavaScript to actually enable navigation or other crucial means.&lt;/p&gt;

&lt;p&gt;As far as the sticky header is concerned, the shown trick only works in scenarios like ours. If you need more transformations then finding a good workaround might be more difficult. In the future that may change, but for now &lt;code&gt;position: sticky&lt;/code&gt; is quite limited and requires such tricks to also have scenarios such as ours covered.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>html</category>
      <category>css</category>
    </item>
    <item>
      <title>🧠 50 Articles to Master Web Dev</title>
      <dc:creator>Florian Rappl</dc:creator>
      <pubDate>Fri, 20 Sep 2024 16:25:02 +0000</pubDate>
      <link>https://forem.com/florianrappl/50-articles-to-master-web-dev-4jhl</link>
      <guid>https://forem.com/florianrappl/50-articles-to-master-web-dev-4jhl</guid>
      <description>&lt;p&gt;&lt;em&gt;&lt;a href="https://www.freepik.com/free-vector/gradient-step-illustration_37443122.htm#fromView=search&amp;amp;page=1&amp;amp;position=9&amp;amp;uuid=034a1fce-8fa5-40fe-9832-045f25551c3a" rel="noopener noreferrer"&gt;Image by freepik&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This year I started a new series on &lt;a href="https://www.linkedin.com/in/florian-rappl/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; - "Advanced Links for Frontend". Each issue has 10 links to outstanding posts / articles. This bundle contains the links from the last 5 issues (issue 51 to issue 55).&lt;/p&gt;

&lt;p&gt;I hope you enjoy this collection. Let me know in the comments which of these articles is your favorite (and why).&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 51
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Fixing a Bug in Google Chrome as a First-Time Contributor&lt;/strong&gt; (&lt;a href="https://cprimozic.net/blog/fixing-a-bug-in-google-chrome/" rel="noopener noreferrer"&gt;https://cprimozic.net/blog/fixing-a-bug-in-google-chrome/&lt;/a&gt;) by Casey Primozic&lt;br&gt;
The last time I had a look at the Chromium codebase was years ago - and it is massive. So much respect to the author for getting in there!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Only Widely Recognized JavaScript Feature Ever Deprecated&lt;/strong&gt; (&lt;a href="https://www.trevorlasn.com/blog/the-only-javascript-feature-that-was-deprecated/" rel="noopener noreferrer"&gt;https://www.trevorlasn.com/blog/the-only-javascript-feature-that-was-deprecated/&lt;/a&gt;) by Trevor Indrek Lasn&lt;br&gt;
I am happy to say that I don't miss "with". I actually only used it once; and even though it made sense for in that case, there would have been other options.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;React Email 3.0&lt;/strong&gt; (&lt;a href="https://resend.com/blog/react-email-3" rel="noopener noreferrer"&gt;https://resend.com/blog/react-email-3&lt;/a&gt;) by Gabriel Miranda&lt;br&gt;
Fantastic changes, superb release!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementing React From Scratch&lt;/strong&gt; (&lt;a href="https://www.rob.directory/blog/react-from-scratch" rel="noopener noreferrer"&gt;https://www.rob.directory/blog/react-from-scratch&lt;/a&gt;) by Robby Pruzan&lt;br&gt;
Been there, done that. As usual, coming up with something that works is not hard - coming up with something that works as good as the original is difficult.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Developer tools are different than tools for any other profession&lt;/strong&gt; (&lt;a href="https://mxstbr.com/notes/developer-tools" rel="noopener noreferrer"&gt;https://mxstbr.com/notes/developer-tools&lt;/a&gt;) by Max Stoiber&lt;br&gt;
If Max says so!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scroll Snap Events&lt;/strong&gt; (&lt;a href="https://developer.chrome.com/blog/scroll-snap-events" rel="noopener noreferrer"&gt;https://developer.chrome.com/blog/scroll-snap-events&lt;/a&gt;) by Adam Argyle&lt;br&gt;
Funny - just a couple of weeks after I'd needed that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;State of JavaScript: Insights from the latest JavaScript developer survey&lt;/strong&gt; (&lt;a href="https://www.infoworld.com/article/3486850/state-of-javascript-insights-from-the-latest-javascript-community-survey.html" rel="noopener noreferrer"&gt;https://www.infoworld.com/article/3486850/state-of-javascript-insights-from-the-latest-javascript-community-survey.html&lt;/a&gt;) by Matthew Tyson&lt;br&gt;
Surprised that the Bun bundler gets a positive rating. That it does not even print some elemental error messages is a red flag for me.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;50 TypeScript F!ck Ups Book&lt;/strong&gt; (&lt;a href="https://github.com/azat-co/50-ts/" rel="noopener noreferrer"&gt;https://github.com/azat-co/50-ts/&lt;/a&gt;) by Azat Mardan&lt;br&gt;
I like the collection. Definitely worth supporting the author!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common misconceptions about how to optimize LCP&lt;/strong&gt; (&lt;a href="https://web.dev/blog/common-misconceptions-lcp" rel="noopener noreferrer"&gt;https://web.dev/blog/common-misconceptions-lcp&lt;/a&gt;) by Brendan Kenny&lt;br&gt;
The images part, unfortunately, is underrated. Having just optimized a web app last week the images optimization part took the project fom a mid 70s rating to a 99 rating in lighthouse. In general I agree though.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Elastic Overflow Scrolling&lt;/strong&gt; (&lt;a href="https://css-tricks.com/elastic-overflow-scrolling/" rel="noopener noreferrer"&gt;https://css-tricks.com/elastic-overflow-scrolling/&lt;/a&gt;) by Dave Seidman&lt;br&gt;
While I don't see it being essential for the Y axis, I think this technique is useful for carousels / on the X axis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 52
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Compilation of JavaScript to Wasm, Part 3: Partial Evaluation&lt;/strong&gt; (&lt;a href="https://cfallin.org/blog/2024/08/28/weval/" rel="noopener noreferrer"&gt;https://cfallin.org/blog/2024/08/28/weval/&lt;/a&gt;) by Chris Fallin&lt;br&gt;
The topic sounds more exotic than it is - personally, I think this will be quite standard in a couple of years.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Material UI v6 is out now 🎉&lt;/strong&gt; (&lt;a href="https://mui.com/blog/material-ui-v6-is-out/" rel="noopener noreferrer"&gt;https://mui.com/blog/material-ui-v6-is-out/&lt;/a&gt;) by Material UI&lt;br&gt;
Great to see that MUI is still progressing!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Announcing Rspack 1.0&lt;/strong&gt; (&lt;a href="https://rspack.dev/blog/announcing-1-0" rel="noopener noreferrer"&gt;https://rspack.dev/blog/announcing-1-0&lt;/a&gt;) by rspack&lt;br&gt;
Wonderful milestone - great project! More than 80% of the top 50 plugins for Webpack are supported - so chances are high that you can migrate quite smoothly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Frontend Resources V2! 🚀&lt;/strong&gt; (&lt;a href="https://dev.to/miguelrodriguezp99/frontend-resources-v2-57mj"&gt;https://dev.to/miguelrodriguezp99/frontend-resources-v2-57mj&lt;/a&gt;) by &lt;a class="mentioned-user" href="https://dev.to/miguelrodriguezp99"&gt;@miguelrodriguezp99&lt;/a&gt; &lt;br&gt;
Collection of useful tools and libraries to simplify your development life.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;New to the web platform in August&lt;/strong&gt; (&lt;a href="https://web.dev/blog/web-platform-08-2024" rel="noopener noreferrer"&gt;https://web.dev/blog/web-platform-08-2024&lt;/a&gt;) by Rachel Andrew&lt;br&gt;
In the west the ruby element is quite unknown, but even here it can be super useful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When 3rd party JavaScript attacks&lt;/strong&gt; (&lt;a href="https://changelog.com/jsparty/336" rel="noopener noreferrer"&gt;https://changelog.com/jsparty/336&lt;/a&gt;) by Simon Wijckmans&lt;br&gt;
When has a third-party JavaScript never attacked?!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JavaScript Generators Explained, But On A Senior-Level&lt;/strong&gt; (&lt;a href="https://www.reactsquad.io/blog/understanding-generators-in-javascript" rel="noopener noreferrer"&gt;https://www.reactsquad.io/blog/understanding-generators-in-javascript&lt;/a&gt;) by Jan Hesters&lt;br&gt;
They are certainly useful - especially in the pull-stream scenario.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Component testing in Storybook&lt;/strong&gt; (&lt;a href="https://storybook.js.org/blog/component-testing/" rel="noopener noreferrer"&gt;https://storybook.js.org/blog/component-testing/&lt;/a&gt;) by Michael Shilman&lt;br&gt;
Yeah sure - I am not surprised to see this in the Storybook blog.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Faster Pages with React ✨&lt;/strong&gt; (&lt;a href="https://dev.to/smapiot/faster-pages-with-react-h8j"&gt;https://dev.to/smapiot/faster-pages-with-react-h8j&lt;/a&gt;) by &lt;a class="mentioned-user" href="https://dev.to/florianrappl"&gt;@florianrappl&lt;/a&gt; &lt;br&gt;
If you really need more performance - you can always get more performant.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The secret inside One Million Checkboxes&lt;/strong&gt; (&lt;a href="https://eieio.games/essays/the-secret-in-one-million-checkboxes/" rel="noopener noreferrer"&gt;https://eieio.games/essays/the-secret-in-one-million-checkboxes/&lt;/a&gt;) by Nolen Royalty&lt;br&gt;
That was actually a superb read. What a journey! Seems like building this little site has given Nolen stories for the next decade.&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 53
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;CSS-only infinite scrolling carousel animation&lt;/strong&gt; (&lt;a href="https://blog.logto.io/css-only-infinite-scroll" rel="noopener noreferrer"&gt;https://blog.logto.io/css-only-infinite-scroll&lt;/a&gt;) by Gao Sun&lt;br&gt;
Since I have played around with this myself two weeks ago I thought the article was great.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;12 Keys to Write Senior-Level Tests&lt;/strong&gt; (&lt;a href="https://www.reactsquad.io/blog/testing-desiderata-in-javascript" rel="noopener noreferrer"&gt;https://www.reactsquad.io/blog/testing-desiderata-in-javascript&lt;/a&gt;) by Jan Hesters&lt;br&gt;
I think this one is the list to follow after the 10 commandments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MDX with Translations 🐠&lt;/strong&gt; (&lt;a href="https://dev.to/smapiot/mdx-with-translations-157c"&gt;https://dev.to/smapiot/mdx-with-translations-157c&lt;/a&gt;) by &lt;a class="mentioned-user" href="https://dev.to/florianrappl"&gt;@florianrappl&lt;/a&gt; &lt;br&gt;
MDX might be the secret sauce that actually provides the bridge between "just content" and "just code".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inside ECMAScript: JavaScript Standard Gets an Extra Stage&lt;/strong&gt; (&lt;a href="https://thenewstack.io/inside-ecmascript-javascript-standard-gets-an-extra-stage/" rel="noopener noreferrer"&gt;https://thenewstack.io/inside-ecmascript-javascript-standard-gets-an-extra-stage/&lt;/a&gt;) by Mary Branscombe&lt;br&gt;
What else is there to do? Do we really want or need a Frankenstein's monster of a language?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What’s new in React 19&lt;/strong&gt; (&lt;a href="https://vercel.com/blog/whats-new-in-react-19" rel="noopener noreferrer"&gt;https://vercel.com/blog/whats-new-in-react-19&lt;/a&gt;) by Michael Novotny&lt;br&gt;
I'm wondering that myself. Last time I checked it's rather "what will be new in React 19".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Preloading files to reduce download chains in the browser&lt;/strong&gt; (&lt;a href="https://www.lkhrs.com/blog/2024/preloading/" rel="noopener noreferrer"&gt;https://www.lkhrs.com/blog/2024/preloading/&lt;/a&gt;) by Luke Harris&lt;br&gt;
Or just batch them in the backend / at compile-time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The future is standalone!&lt;/strong&gt; (&lt;a href="https://blog.angular.dev/the-future-is-standalone-475d7edbc706" rel="noopener noreferrer"&gt;https://blog.angular.dev/the-future-is-standalone-475d7edbc706&lt;/a&gt;) by Alex Rickabaugh&lt;br&gt;
I think the future is standalone since more than a decade, but I am happy that finally Angular recognizes this, too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Introducing &lt;a class="mentioned-user" href="https://dev.to/bramus"&gt;@bramus&lt;/a&gt;/style-observer, a MutationObserver for CSS&lt;/strong&gt; (&lt;a href="https://www.bram.us/2024/08/31/introducing-bramus-style-observer-a-mutationobserver-for-css/" rel="noopener noreferrer"&gt;https://www.bram.us/2024/08/31/introducing-bramus-style-observer-a-mutationobserver-for-css/&lt;/a&gt;) by Bramus Van Damme&lt;br&gt;
While I applaud the effort I will definitely avoid scenarios that force me into using it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;i-html&lt;/strong&gt; (&lt;a href="https://www.keithcirkel.co.uk/i-html/" rel="noopener noreferrer"&gt;https://www.keithcirkel.co.uk/i-html/&lt;/a&gt;) by Keith Cirkel&lt;br&gt;
This is great - but pi-component can already do that (and more). Still happy that the need for fragment inclusion is becoming more recognized.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build-time Components&lt;/strong&gt; (&lt;a href="https://codehike.org/blog/build-time-components" rel="noopener noreferrer"&gt;https://codehike.org/blog/build-time-components&lt;/a&gt;) by Rodrigo Pombo&lt;br&gt;
Alright - what did I say about MDX?! But great write-up and it also goes into the different composition modes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 54
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Look out, kids: PHP is the new JavaScript&lt;/strong&gt; (&lt;a href="https://www.mux.com/blog/php-is-the-new-javascript" rel="noopener noreferrer"&gt;https://www.mux.com/blog/php-is-the-new-javascript&lt;/a&gt;) by Dave Kiss&lt;br&gt;
No, it's not. But generally it's nice to see PHP (and its ecosystem) evolving.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An SSR Performance Showdown&lt;/strong&gt; (&lt;a href="https://blog.platformatic.dev/ssr-performance-showdown" rel="noopener noreferrer"&gt;https://blog.platformatic.dev/ssr-performance-showdown&lt;/a&gt;) by Matteo Collina&lt;br&gt;
Long story short: If you need something simple, choose something that does less work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Managing Angular&lt;/strong&gt; (&lt;a href="https://blog.mgechev.com/2024/08/25/managing-angular/" rel="noopener noreferrer"&gt;https://blog.mgechev.com/2024/08/25/managing-angular/&lt;/a&gt;) by Minko Gechev&lt;br&gt;
Certainly a great read. The only thing I missed is the objective - what's the goal? Seems to me that Angular is still playing catchup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Oops, I accidentally made our website faster by switching to Remix&lt;/strong&gt; (&lt;a href="https://echobind.com/post/oops-i-accidentally-made-our-website-faster-by-switching-to-remix" rel="noopener noreferrer"&gt;https://echobind.com/post/oops-i-accidentally-made-our-website-faster-by-switching-to-remix&lt;/a&gt;) by Alex Anderson&lt;br&gt;
Maybe drop frameworks all together to make it even faster!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Building the Same App Using Various Web Frameworks&lt;/strong&gt; (&lt;a href="https://eugeneyan.com/writing/web-frameworks/" rel="noopener noreferrer"&gt;https://eugeneyan.com/writing/web-frameworks/&lt;/a&gt;) by Eugene Yan&lt;br&gt;
Ah another comparison. Seems like this is the main trend for the current week. Spoiler: Performance is not considered in this one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;New Environment API&lt;/strong&gt; (&lt;a href="https://main.vitejs.dev/guide/api-environment" rel="noopener noreferrer"&gt;https://main.vitejs.dev/guide/api-environment&lt;/a&gt;) by Vite&lt;br&gt;
With the next iteration of Vite we'll get some exciting new APIs!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;11ty is joining Font Awesome&lt;/strong&gt; (&lt;a href="https://www.11ty.dev/blog/eleventy-font-awesome/" rel="noopener noreferrer"&gt;https://www.11ty.dev/blog/eleventy-font-awesome/&lt;/a&gt;) by Zach Leatherman&lt;br&gt;
With this partnership the foundation of 11ty is solidified even more. Great work!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Svelte 5 signals fix its glitchy and inconsistent reactivity&lt;/strong&gt; (&lt;a href="https://www.webdevladder.net/blog/svelte-5-signals-fix-its-glitchy-and-inconsistent-reactivity" rel="noopener noreferrer"&gt;https://www.webdevladder.net/blog/svelte-5-signals-fix-its-glitchy-and-inconsistent-reactivity&lt;/a&gt;) by Ryan Atkinson&lt;br&gt;
Another reason to switch to Svelte 5 as soon as possible - runes are really wonderful!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rethinking CSS in JS&lt;/strong&gt; (&lt;a href="https://dev.to/black7375/rethinking-css-in-js-5dip"&gt;https://dev.to/black7375/rethinking-css-in-js-5dip&lt;/a&gt;) by &lt;a class="mentioned-user" href="https://dev.to/black7375"&gt;@black7375&lt;/a&gt; &lt;br&gt;
One of the longer articles at dev.to, but most certainly worth the read.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tailwind CSS vs Pico CSS&lt;/strong&gt; (&lt;a href="https://edofic.com/posts/2022-01-18-tailwind-vs-pico/" rel="noopener noreferrer"&gt;https://edofic.com/posts/2022-01-18-tailwind-vs-pico/&lt;/a&gt;) by Andraž Bajt&lt;br&gt;
I am not sure if this is a fair comparison at all, but we are back to "if you need less features, use something with less features".&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 55
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Understanding Concurrency, Parallelism and JS&lt;/strong&gt; (&lt;a href="https://www.rugu.dev/en/blog/concurrency-and-parallelism/" rel="noopener noreferrer"&gt;https://www.rugu.dev/en/blog/concurrency-and-parallelism/&lt;/a&gt;) by Uğur Erdem Seyfi&lt;br&gt;
In the last 15 years (and surely beyond that) this has been discussed every year - but I feel the topic has never been more relevant than today.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MDX in Next.js&lt;/strong&gt; (&lt;a href="https://spacejelly.dev/posts/mdx-in-nextjs" rel="noopener noreferrer"&gt;https://spacejelly.dev/posts/mdx-in-nextjs&lt;/a&gt;) by Colby Fayock&lt;br&gt;
MDX is indeed a great format for content - it's very close to the sweet spot between just static markup and rich interactivity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cleaner JavaScript promises with safe-await&lt;/strong&gt; (&lt;a href="https://alexjpate.com/posts/cleaner-promises-with-safe-await" rel="noopener noreferrer"&gt;https://alexjpate.com/posts/cleaner-promises-with-safe-await&lt;/a&gt;) by Alex Pate&lt;br&gt;
I am not sure it that's indeed cleaner (for everyone's taste), but I like it. Note that something similar is debated in TC39.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Announcing TypeScript 5.6&lt;/strong&gt; (&lt;a href="https://devblogs.microsoft.com/typescript/announcing-typescript-5-6/" rel="noopener noreferrer"&gt;https://devblogs.microsoft.com/typescript/announcing-typescript-5-6/&lt;/a&gt;) by Daniel Rosenwasser&lt;br&gt;
Whoop whoop. Let's all upgrade. Seriously - good new version, but nothing life changing. Back to work!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The web's clipboard, and how it stores data of different types&lt;/strong&gt; (&lt;a href="https://alexharri.com/blog/clipboard" rel="noopener noreferrer"&gt;https://alexharri.com/blog/clipboard&lt;/a&gt;) by Alex Harri&lt;br&gt;
Years ago this was a great struggle, but the async clipboard API is indeed quite nice and useful. Great writeup!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CSS display contents&lt;/strong&gt; (&lt;a href="https://ishadeed.com/article/display-contents/" rel="noopener noreferrer"&gt;https://ishadeed.com/article/display-contents/&lt;/a&gt;) by Ahmad Shadeed&lt;br&gt;
My favorite CSS author is back - and now this picks up one of my favorite CSS features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Learning to Reason with LLMs&lt;/strong&gt; (&lt;a href="https://openai.com/index/learning-to-reason-with-llms/" rel="noopener noreferrer"&gt;https://openai.com/index/learning-to-reason-with-llms/&lt;/a&gt;) by OpenAI&lt;br&gt;
Keep in mind that it's unreasonable to call yourself open but do everything closed. There is an open source variation of this, too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Undeniable Utility Of CSS :has&lt;/strong&gt; (&lt;a href="https://www.joshwcomeau.com/css/has/" rel="noopener noreferrer"&gt;https://www.joshwcomeau.com/css/has/&lt;/a&gt;) by Josh Comeau&lt;br&gt;
Honestly, :has is exactly the selected we needed. The number of (previously) "impossible" selectors that I created with it speaks for itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Passwords have problems, but passkeys have more&lt;/strong&gt; (&lt;a href="https://world.hey.com/dhh/passwords-have-problems-but-passkeys-have-more-95285df9" rel="noopener noreferrer"&gt;https://world.hey.com/dhh/passwords-have-problems-but-passkeys-have-more-95285df9&lt;/a&gt;) by David Heinemeier Hansson&lt;br&gt;
I was also quite excited about passkeys first. But I never use them for the exact reasons that are outlined in the post.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A (more) Modern CSS Reset&lt;/strong&gt; (&lt;a href="https://piccalil.li/blog/a-more-modern-css-reset/" rel="noopener noreferrer"&gt;https://piccalil.li/blog/a-more-modern-css-reset/&lt;/a&gt;) by Andy Bell&lt;br&gt;
I have not used a CSS reset in ages. Might be useful - but just being explicit with some declarations (esp. if inconsistencies between browsers are seen) is usually enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;These are all outstanding articles by masterful authors. I enjoyed reading them all - I hope you did find something in there, too.&lt;/p&gt;

&lt;p&gt;👉 Follow me on &lt;a href="https://www.linkedin.com/in/florian-rappl/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://twitter.com/FlorianRappl" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, or here for more to come.&lt;/p&gt;

&lt;p&gt;🙏 Thanks to all the authors and contributors for their hard work!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>node</category>
    </item>
    <item>
      <title>MDX with Translations 🐠</title>
      <dc:creator>Florian Rappl</dc:creator>
      <pubDate>Tue, 03 Sep 2024 15:13:11 +0000</pubDate>
      <link>https://forem.com/smapiot/mdx-with-translations-157c</link>
      <guid>https://forem.com/smapiot/mdx-with-translations-157c</guid>
      <description>&lt;p&gt;In recent years the need for some easy yet flexible format for simple static content has grown. Originally, HTML was meant for that - but let's be honest: it is neither simple, nor flexible. There have been plenty replacement proposals - as pretty much every CMS comes with its own dialect.&lt;/p&gt;

&lt;p&gt;One good contender for static content that can be read and rendered nicely is Markdown. However, it has quite a bit of shortcomings. Most notably, Markdown is not fully specified - leading to multiple dialects that exist. Furthermore, many necessary things are only available in form of non-standard extensions. Finally, using custom components within Markdown is not possible.&lt;/p&gt;

&lt;p&gt;This is where &lt;a href="https://mdxjs.com/" rel="noopener noreferrer"&gt;MDX&lt;/a&gt; comes into play. It's essentially a hybrid of JSX / React and a well-specified dialect of Markdown. Essentially, this allows writing texts that are as simple as plain Markdown, as well as creating complex components as you might have done in full JSX.&lt;/p&gt;

&lt;h2&gt;
  
  
  Website Structure
&lt;/h2&gt;

&lt;p&gt;We build upon the structure set up in our recently published article &lt;a href="https://dev.to/smapiot/faster-pages-with-react-h8j"&gt;faster pages with React&lt;/a&gt; and &lt;a href="https://smapiot.com/blog/2019-10-19-how-we-build-smapiot-com/" rel="noopener noreferrer"&gt;our original blog post&lt;/a&gt; from 2019. In this structure we have all the pages placed in their path-relative order using React for each page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw9kcsj523wza8yk93vi1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw9kcsj523wza8yk93vi1.png" alt="Structure of the pages" width="217" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now there are two things that we want to take care of:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Improve the content writing (and reading) for each employee at smapiot&lt;/li&gt;
&lt;li&gt;Simplify translations; right now the structure requires duplicating pages (placing them with different / translated content in the "de" and "en" folders).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For the former we want to leverage MDX - for the latter we need to come up with a solution that allows us to have a flat structure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating MDX
&lt;/h2&gt;

&lt;p&gt;Bringing MDX into the solution is actually quite straight forward. The &lt;code&gt;@mdx-js/mdx&lt;/code&gt; package contains everything to compile and work with MDX files. However, as we are already using a bundler (Vite), we can just rely on the specific plugin that exists for that bundler.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i @mdx-js/rollup &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why are we installing a package called &lt;code&gt;rollup&lt;/code&gt; if our bundler is Vite? It turns out, that Vite is actually just a build-tool - for the actual bundling two other things are used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;esbuild to bundle/process anything in the third-party packages (as well as use it, e.g., on the config file)&lt;/li&gt;
&lt;li&gt;rollup to bundle/process the user code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hence the rollup plugin - which is all we need.&lt;/p&gt;

&lt;p&gt;The integration into our &lt;em&gt;vite.config.mjs&lt;/em&gt; file looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;codegen&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite-plugin-codegen&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;mdx&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@mdx-js/rollup&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;assetsInlineLimit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;codegen&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nf"&gt;mdx&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that we are not providing any options right now. It just works!&lt;/p&gt;

&lt;p&gt;So what can we do here? Consider one of our previous pages, the legal disclaimer (who doesn't love legal pages?!):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@smapiot/components/lib/basic/Page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Legal Disclaimer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;legal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Legal Disclaimer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;smapiot - Legal Disclaimer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Page&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Legal Disclaimer&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Liability for Contents&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        The contents of our pages have been compiled with the greatest care. However, we cannot guarantee for accuracy,
        completeness or topicality of the contents. As service providers, we are liable for own contents of these
        websites according to sec. 7, paragraph 1 German Telemedia Act (TMG). However, according to sec. 8 to 10 German
        Telemedia Act (TMG), service providers are not obligated to permanently monitor submitted or stored information
        or to search for evidences that indicate illegal activities. Legal obligations to removing information or to
        blocking the use of information remain unchallenged. In this case, liability is only possible at the time of
        knowledge about a specific violation of law. Illegal contents will be removed immediately at the time we get
        knowledge of them.
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Liability for Links&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Our web pages include links to external third party websites. We have no influence on the contents of those
        external websites, therefore we cannot guarantee for those contents. Providers or administrators of linked
        websites are always responsible for their own contents. The linked websites had been checked for possible
        violations of law at the time of the establishment of the link. Illegal contents were not detected at the time
        of the linking. A permanent monitoring of the contents of linked websites cannot be imposed without reasonable
        indications that there has been a violation of law. Illegal links will be removed immediately at the time we get
        knowledge of them.
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Copyright&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Contents and compilations published on these websites by the providers are subject to German copyright laws.
        Reproduction, editing, distribution as well as the use of any kind outside the scope of the copyright law
        require a written permission of the author or originator. Downloads and copies of these websites are permitted
        for private use only. The commercial use of our contents without permission of the originator is prohibited.
        Copyright laws of third parties are respected as long as the contents on these websites do not originate from
        the provider. Contributions of third parties on this site are indicated as such. However, if you notice any
        violations of copyright law, please inform us. Such contents will be removed immediately.
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This isn't too bad! What we can now do is to rename it from &lt;em&gt;Disclaimer.tsx&lt;/em&gt; to &lt;em&gt;Disclaimer.mdx&lt;/em&gt; and change its content to become:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const meta = {
  title: 'Legal Disclaimer',
  legal: 'Legal Disclaimer',
};

&amp;lt;section className="container"&amp;gt;
  # Legal Disclaimer

  ### Liability for Contents

  The contents of our pages have been compiled with the greatest care. However, we cannot guarantee for accuracy, completeness or topicality of the contents. As service providers, we are liable for own contents of these websites according to sec. 7, paragraph 1 German Telemedia Act (TMG). However, according to sec. 8 to 10 German Telemedia Act (TMG), service providers are not obligated to permanently monitor submitted or stored information or to search for evidences that indicate illegal activities. Legal obligations to removing information or to blocking the use of information remain unchallenged. In this case, liability is only possible at the time of knowledge about a specific violation of law. Illegal contents will be removed immediately at the time we get knowledge of them.

  ### Liability for Links

  Our web pages include links to external third party websites. We have no influence on the contents of those external websites, therefore we cannot guarantee for those contents. Providers or administrators of linked websites are always responsible for their own contents. The linked websites had been checked for possible violations of law at the time of the establishment of the link. Illegal contents were not detected at the time of the linking. A permanent monitoring of the contents of linked websites cannot be imposed without reasonable indications that there has been a violation of law. Illegal links will be removed immediately at the time we get knowledge of them.

  ### Copyright

  Contents and compilations published on these websites by the providers are subject to German copyright laws. Reproduction, editing, distribution as well as the use of any kind outside the scope of the copyright law require a written permission of the author or originator. Downloads and copies of these websites are permitted for private use only. The commercial use of our contents without permission of the originator is prohibited. Copyright laws of third parties are respected as long as the contents on these websites do not originate from the provider. Contributions of third parties on this site are indicated as such. However, if you notice any violations of copyright law, please inform us. Such contents will be removed immediately.
&amp;lt;/section&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Much easier to read! Note that unnecessary imports such as &lt;code&gt;react&lt;/code&gt; could be removed, while the boilerplate wrapper component &lt;code&gt;Page&lt;/code&gt; will now be automatically inserted.&lt;/p&gt;

&lt;p&gt;But there was a second thing we needed, right? What about improvements for the localization / page structure?&lt;/p&gt;

&lt;p&gt;Let's see what we can do here!&lt;/p&gt;

&lt;h2&gt;
  
  
  Providing Translations
&lt;/h2&gt;

&lt;p&gt;What if we would just put the localization strings all in a little sidecar? For instance, for a file like &lt;em&gt;Disclaimer.mdx&lt;/em&gt; we'd also have a file &lt;em&gt;Disclaimer.yml&lt;/em&gt;. In this file we could place translations according to the languages.&lt;/p&gt;

&lt;p&gt;The whole structure could then look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fepvq7566frpfpph1vq7t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fepvq7566frpfpph1vq7t.png" alt="Renewed structure of the pages" width="237" height="543"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Where an individual file, e.g., for &lt;em&gt;Disclaimer.yml&lt;/em&gt; could be written as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;de&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;content$&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;# Haftungsausschluss&lt;/span&gt;

    &lt;span class="s"&gt;### Haftung für Inhalte&lt;/span&gt;

    &lt;span class="s"&gt;Die Inhalte unserer Seiten wurden mit größter Sorgfalt erstellt. Für die Richtigkeit, Vollständigkeit und Aktualität der Inhalte können wir jedoch keine Gewähr übernehmen. Als Diensteanbieter sind wir gemäß § 7 Abs.1 TMG für eigene Inhalte auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich. Nach §§ 8 bis 10 TMG sind wir als Diensteanbieter jedoch nicht verpflichtet, übermittelte oder gespeicherte fremde Informationen zu überwachen oder nach Umständen zu forschen, die auf eine rechtswidrige Tätigkeit hinweisen. Verpflichtungen zur Entfernung oder Sperrung der Nutzung von Informationen nach den allgemeinen Gesetzen bleiben hiervon unberührt. Eine diesbezügliche Haftung ist jedoch erst ab dem Zeitpunkt der Kenntnis einer konkreten Rechtsverletzung möglich. Bei Bekanntwerden von entsprechenden Rechtsverletzungen werden wir diese Inhalte umgehend entfernen.&lt;/span&gt;

    &lt;span class="s"&gt;### Haftung für Links&lt;/span&gt;

    &lt;span class="s"&gt;Unser Angebot enthält Links zu externen Webseiten Dritter, auf deren Inhalte wir keinen Einfluss haben. Deshalb können wir für diese fremden Inhalte auch keine Gewähr übernehmen. Für die Inhalte der verlinkten Seiten ist stets der jeweilige Anbieter oder Betreiber der Seiten verantwortlich. Die verlinkten Seiten wurden zum Zeitpunkt der Verlinkung auf mögliche Rechtsverstöße überprüft. Rechtswidrige Inhalte waren zum Zeitpunkt der Verlinkung nicht erkennbar. Eine permanente inhaltliche Kontrolle der verlinkten Seiten ist jedoch ohne konkrete Anhaltspunkte einer Rechtsverletzung nicht zumutbar. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Links umgehend entfernen.&lt;/span&gt;

    &lt;span class="s"&gt;### Urheberrecht&lt;/span&gt;

    &lt;span class="s"&gt;Die durch die Seitenbetreiber erstellten Inhalte und Werke auf diesen Seiten unterliegen dem deutschen Urheberrecht. Die Vervielfältigung, Bearbeitung, Verbreitung und jede Art der Verwertung außerhalb der Grenzen des Urheberrechtes bedürfen der schriftlichen Zustimmung des jeweiligen Autors bzw. Erstellers. Downloads und Kopien dieser Seite sind nur für den privaten, nicht kommerziellen Gebrauch gestattet. Soweit die Inhalte auf dieser Seite nicht vom Betreiber erstellt wurden, werden die Urheberrechte Dritter beachtet. Insbesondere werden Inhalte Dritter als solche gekennzeichnet. Sollten Sie trotzdem auf eine Urheberrechtsverletzung aufmerksam werden, bitten wir um einen entsprechenden Hinweis. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Inhalte umgehend entfernen.&lt;/span&gt;
&lt;span class="na"&gt;en&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;content$&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;# Legal Disclaimer&lt;/span&gt;

    &lt;span class="s"&gt;### Liability for Contents&lt;/span&gt;

    &lt;span class="s"&gt;The contents of our pages have been compiled with the greatest care. However, we cannot guarantee for accuracy, completeness or topicality of the contents. As service providers, we are liable for own contents of these websites according to sec. 7, paragraph 1 German Telemedia Act (TMG). However, according to sec. 8 to 10 German Telemedia Act (TMG), service providers are not obligated to permanently monitor submitted or stored information or to search for evidences that indicate illegal activities. Legal obligations to removing information or to blocking the use of information remain unchallenged. In this case, liability is only possible at the time of knowledge about a specific violation of law. Illegal contents will be removed immediately at the time we get knowledge of them.&lt;/span&gt;

    &lt;span class="s"&gt;### Liability for Links&lt;/span&gt;

    &lt;span class="s"&gt;Our web pages include links to external third party websites. We have no influence on the contents of those external websites, therefore we cannot guarantee for those contents. Providers or administrators of linked websites are always responsible for their own contents. The linked websites had been checked for possible violations of law at the time of the establishment of the link. Illegal contents were not detected at the time of the linking. A permanent monitoring of the contents of linked websites cannot be imposed without reasonable indications that there has been a violation of law. Illegal links will be removed immediately at the time we get knowledge of them.&lt;/span&gt;

    &lt;span class="s"&gt;### Copyright&lt;/span&gt;

    &lt;span class="s"&gt;Contents and compilations published on these websites by the providers are subject to German copyright laws. Reproduction, editing, distribution as well as the use of any kind outside the scope of the copyright law require a written permission of the author or originator. Downloads and copies of these websites are permitted for private use only. The commercial use of our contents without permission of the originator is prohibited. Copyright laws of third parties are respected as long as the contents on these websites do not originate from the provider. Contributions of third parties on this site are indicated as such. However, if you notice any violations of copyright law, please inform us. Such contents will be removed immediately.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this file a set of conventions exist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The top-level keys must be valid languages (right now only &lt;code&gt;de&lt;/code&gt; and &lt;code&gt;en&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The keys can be nested, i.e., objects / arrays are allowed&lt;/li&gt;
&lt;li&gt;When a key ends with a &lt;code&gt;$&lt;/code&gt; sign it will be interpreted as Markdown (specifically, MDX)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How does the MDX file look with such a sidecar file?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const meta = {
  title: 'Legal Disclaimer',
  legal: 'Legal Disclaimer',
};

&amp;lt;section className="container"&amp;gt;
  {locale.content$}
&amp;lt;/section&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now this looks appealing!&lt;/p&gt;

&lt;p&gt;For integrating the localization we still need to do something. See the use of &lt;code&gt;locale&lt;/code&gt; in the code above. But how does &lt;code&gt;locale&lt;/code&gt; enter the landscape in the file? After all, we don't see it!&lt;/p&gt;

&lt;p&gt;Turns out we can manipulate the generated code by MDX. Let's configure the tool a bit by adding a custom plugin to the &lt;code&gt;recmaPlugins&lt;/code&gt; option. This allows us to have full control over the generated abstract syntax tree (AST), which is then used to generate the actual code representing the MDX file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;codegen&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite-plugin-codegen&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;mdx&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@mdx-js/rollup&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;localize&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/tools/localize.mjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;assetsInlineLimit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;codegen&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nf"&gt;mdx&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;recmaPlugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;localize&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The imported &lt;code&gt;localize&lt;/code&gt; function is the actual plugin - which just yields another function - the so-called transformer. The transformer is responsible for manipulating the AST.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;transform&lt;/code&gt; function in the next snippet receives the AST and the virtual file (i.e., it's name, content, ...) of the MDX file that is currently being handled.&lt;/p&gt;

&lt;p&gt;Let's see the code before we go over what it does:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;compileSync&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@mdx-js/mdx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loadLocale&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./localization.mjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fromMarkdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="nf"&gt;compileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;development&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;recmaPlugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[,&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CallExpression&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;callee&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ObjectExpression&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ArrayExpression&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ObjectExpression&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Property&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Identifier&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;getExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;init&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;})),&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;boolean&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Literal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// uses potentially markdown&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;fromMarkdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Literal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Literal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;vfile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;language&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WEBSITE_LOCALE&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;vfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;locale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;loadLocale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findLastIndex&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ImportDeclaration&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imprt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ImportDeclaration&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react/jsx-runtime&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requiredImports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_jsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_jsxs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jsxs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_Fragment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Fragment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requiredImport&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;requiredImports&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;original&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;requiredImport&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;imprt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;specifiers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ImportSpecifier&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;imported&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;original&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;imprt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;specifiers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ImportSpecifier&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;imported&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Identifier&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;original&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;local&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Identifier&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;VariableDeclaration&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;const&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;declarations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;VariableDeclarator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Identifier&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;locale&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;init&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;getExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;plugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;plugin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks more complicated than it needs to be! In the end, it all boils down to changing the AST to&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;obtain the &lt;code&gt;locale&lt;/code&gt; for the document&lt;/li&gt;
&lt;li&gt;insert potentially missing named imports (to fully support the generated Markdown / content, if any) into the &lt;code&gt;react/jsx-runtime&lt;/code&gt; import&lt;/li&gt;
&lt;li&gt;insert the &lt;code&gt;locale&lt;/code&gt; declaration - first thing &lt;em&gt;after&lt;/em&gt; the imports (this way you can use &lt;code&gt;locale&lt;/code&gt; pretty much everywhere in the document&lt;/li&gt;
&lt;li&gt;initialize the &lt;code&gt;locale&lt;/code&gt; variable to be the object we know; with exception of Markdown strings (suffixed with &lt;code&gt;$&lt;/code&gt;): these are transformed into an IIFE keeping the original MDX code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A good way to see what we are doing can be observed by using &lt;a href="https://mdxjs.com/playground/" rel="noopener noreferrer"&gt;the MDX playground&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8c58rl9ib54w7cm9geba.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8c58rl9ib54w7cm9geba.png" alt="Compiled code" width="800" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see the compiled code is a bit strange, but can be mapped nicely to our original MDX file.&lt;/p&gt;

&lt;p&gt;In contrast, the view that we are actually most interested about is the stage before the code is in that compiled state. It's the "esast" view in the playground (i.e., the AST of the ESTree stage).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvci3lla78gbyegntv56e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvci3lla78gbyegntv56e.png" alt="ESTree representation" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What we want to achieve with our plugin is that we manipulate the start. Unfortunately, directly in MDX code we'd need to use an &lt;code&gt;export&lt;/code&gt; for that, but by manipulating the AST directly we actually don't need it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Febj3ranmzxh6izea13tf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Febj3ranmzxh6izea13tf.png" alt="Concept of what we want to do" width="800" height="518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To obtain the &lt;code&gt;locale&lt;/code&gt; variable / object we the &lt;code&gt;loadLocale&lt;/code&gt; function from a dedicated module.&lt;/p&gt;

&lt;p&gt;This module does:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read and parse the local / file specific translations&lt;/li&gt;
&lt;li&gt;Obtain the language-specific translations of the local file&lt;/li&gt;
&lt;li&gt;Read and parse the global translations&lt;/li&gt;
&lt;li&gt;Obtain the language-specific translations of the global file&lt;/li&gt;
&lt;li&gt;Merge with local translations being regarded higher&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For obtaining the language-specific translations we choose a base translation (in our case &lt;code&gt;en&lt;/code&gt;) and "walk" through the object. The current language (let's say &lt;code&gt;de&lt;/code&gt;) then either overrides the base translation or just uses the snippet obtained from the base translation.&lt;/p&gt;

&lt;p&gt;You can think of this process as a deep merge with the base translation being the original.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;readFile&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs/promises&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;parse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;yaml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getLocalization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error reading YAML file:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;mergeLocale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;baseLocale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newLocale&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;newLocale&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;baseLocale&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;baseLocale&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newLocale&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;mergeLocale&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}),&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getLocale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;locales&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;baseLocale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;locales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;en&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;locales&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newLocale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;locales&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;mergeLocale&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="nx"&gt;baseLocale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newLocale&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;baseLocale&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;loadLocale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.mdx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;globalFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;..&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;global.yml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;targetFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.mdx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.yml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;globals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getLocalization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;globalFn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;locales&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getLocalization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetFn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nf"&gt;getLocale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nf"&gt;getLocale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;locales&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;language&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The global translations are placed in the folder above the &lt;code&gt;pages&lt;/code&gt;. The name of the file is &lt;em&gt;global.yml&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;For the &lt;em&gt;global.yml&lt;/em&gt; we only have some very common translation terms stored. An example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;de&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;germany&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deutschland&lt;/span&gt;
&lt;span class="na"&gt;en&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;germany&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Germany&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Being able to just change a single file when new translations come (or just changing the structure in one place independent of language changes) is a big deal. For us this was quite important and the new structure reflects that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;With the new approach the pages are much easier to write than beforehand. Also, since we now have a static translation system in place we do not need to duplicate the pages or come up with some complicated system for intermediate components. It's all already done at compile-time in the given structure.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Faster Pages with React ✨</title>
      <dc:creator>Florian Rappl</dc:creator>
      <pubDate>Fri, 30 Aug 2024 08:17:31 +0000</pubDate>
      <link>https://forem.com/smapiot/faster-pages-with-react-h8j</link>
      <guid>https://forem.com/smapiot/faster-pages-with-react-h8j</guid>
      <description>&lt;p&gt;&lt;em&gt;Photo by &lt;a href="https://unsplash.com/@cadop?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Mathew Schwartz&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/time-lapse-photography-of-tunnel-sb7RUrRMaC4?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is the story of our &lt;a href="https://smapiot.com" rel="noopener noreferrer"&gt;homepage&lt;/a&gt; make over to reach a solid lighthouse score. If you want to read how we made the homepage in the first place then &lt;a href="https://smapiot.com/blog/2019-10-19-how-we-build-smapiot-com" rel="noopener noreferrer"&gt;have a look at our blog post from 2019&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Many of the things I write about here can be seen in the &lt;a href="https://dev.to/florianrappl/fast-pages-with-react-27og"&gt;Fast Pages with React&lt;/a&gt; article.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Origins
&lt;/h2&gt;

&lt;p&gt;Our homepage started off as a React SPA. Why? It was 2019 and the UI designer created the components all in React. Plus, it was a super smooth experience that was actually quite acceptable.&lt;/p&gt;

&lt;p&gt;However, while some may argue that a SPA is not good for SEO this was not the reason why we wanted to have a pre-rendered page. SEO seemed actually fine, but some more simple crawlers did not find all the information as it was hidden behind some JavaScript.&lt;/p&gt;

&lt;p&gt;So what can we do here? Well, we can just render everything at build-time using an static-site generation (SSG) approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Going into SSG
&lt;/h2&gt;

&lt;p&gt;We did not want to change the overall content or engine behind the page. After all, the DX was great and we thought that reusability of the components is more important than migrating to the latest SSG framework.&lt;/p&gt;

&lt;p&gt;After the build (back then using the &lt;a href="https://v1.parceljs.org/" rel="noopener noreferrer"&gt;Parcel v1&lt;/a&gt; bundler) was done, we had a post-build process that took the generated &lt;em&gt;index.html&lt;/em&gt; and went through all the detected pages. As our routing is declarative (we already generated the routes from the file system paths) finding the pages was easy.&lt;/p&gt;

&lt;p&gt;For each page we ran simple script that does the following things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Teach Node.js how ESM works (&lt;code&gt;esm&lt;/code&gt; module)&lt;/li&gt;
&lt;li&gt;Allow using TypeScript via &lt;code&gt;ts-node&lt;/code&gt; (our source is using TypeScript)&lt;/li&gt;
&lt;li&gt;Add some globals like &lt;code&gt;document&lt;/code&gt; or &lt;code&gt;localStorage&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Register some additional extensions, e.g., for resolving images as modules in Node.js (these images should resolve to the already generated images from the bundler)&lt;/li&gt;
&lt;li&gt;Evaluate the page - using &lt;code&gt;renderToString&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Replace the app's content container with the pre-rendered page&lt;/li&gt;
&lt;li&gt;Save the HTML of the modified app in a new file that matches the path of the page&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In code this worked as follows:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;writeFileSync&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mkdirSync&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;require&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;esm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ts-node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;compilerOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;commonjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;es6&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;jsx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;importHelpers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;moduleResolution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;transpileOnly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nb"&gt;global&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;XMLHttpRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="err"&gt;{};
&lt;/span&gt;&lt;span class="nc"&gt;global&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;XDomainRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="err"&gt;{};
&lt;/span&gt;&lt;span class="nc"&gt;global&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nb"&gt;global&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sample&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MemoryRouter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;renderToString&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-dom/server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lazy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Loading ...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fragment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useLayoutEffect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setupExtensions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.svg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.jpg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.jpeg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.mp4&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.mp3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.woff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.tiff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.tif&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.xml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;extension&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;extension&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;front&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;front&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.codegen&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;renderApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dist&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sourceModule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sourceModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sourceModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Layout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../scripts/layout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;MemoryRouter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;renderToString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;outPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;makePage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;outDir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&amp;lt;div id="app"&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;.*&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;div&amp;gt;/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;div id="app"&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/div&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;mkdirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;recursive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;writeFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dist&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;setupExtensions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;outPath&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;renderApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dist&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;makePage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The whole &lt;code&gt;process&lt;/code&gt; is used as the given module is called from a forked process. So each page is generated in an isolated process.&lt;/p&gt;

&lt;p&gt;The following diagram illustrates this process.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzmyi9iwmglv40w0bpmke.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzmyi9iwmglv40w0bpmke.png" alt="Pipeline of building the website"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What did we win so far? We have a pre-rendered page that works already and transforms to a SPA. Nice. But not enough for us.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modernizing the Stack
&lt;/h2&gt;

&lt;p&gt;I already described the process as "was". Parcel v1 has not been updated in quite a while and is - from today's point of view - quite slow. It also does not support some modern concepts and should be retired for good.&lt;/p&gt;

&lt;p&gt;As a replacement we've chosen &lt;a href="https://vitejs.dev/" rel="noopener noreferrer"&gt;Vite&lt;/a&gt;. This is a suitable replacement as it comes with a super fast development server and a very well optimized release build.&lt;/p&gt;

&lt;p&gt;Also, since we are using &lt;a href="https://dev.to/florianrappl/getting-bundling-superpowers-using-codegen-2no8"&gt;codegen&lt;/a&gt; for the route retrieval we can still keep using it for Vite.&lt;/p&gt;

&lt;p&gt;After all, the whole configuration for Vite to allow the transition is shown below:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;codegen&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite-plugin-codegen&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;assetsInlineLimit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;codegen&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To avoid Vite's original behavior of inlining smaller assets (which would lead to problems in our SSG behavior) we set the &lt;code&gt;assetsInlineLimit&lt;/code&gt; to 0.&lt;/p&gt;

&lt;p&gt;One thing we also improved when making the transition from Parcel v1 to Vite is that we introduced path aliases. With the configuration above we can write &lt;code&gt;import '@/foo/bar'&lt;/code&gt; instead of going explicitly via the relative path to &lt;code&gt;src/foo/bar&lt;/code&gt;. This makes modules more flexible and easier to maintain.&lt;/p&gt;

&lt;p&gt;Previously, we used a bit of tools (&lt;code&gt;esm&lt;/code&gt;, &lt;code&gt;ts-node&lt;/code&gt;, ...) to actually make the SSG happen. With the new setup it was time to reduce the amount of tools and replace them all with &lt;code&gt;esbuild&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1smz7nws76xc7wh6bzz6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1smz7nws76xc7wh6bzz6.png" alt="New SSG pipeline with esbuild"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The updated code of the SSG kernel module therefore changed a bit, too:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;writeFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mkdir&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs/promises&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;relative&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;runInContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;compile&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./compile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ReactRouter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ReactRouterDom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-router-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;renderToString&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-dom/server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lazy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Loading ...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fragment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useLayoutEffect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;renderApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dist&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;dist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;platform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
        import { MemoryRouter } from "react-router";
        import Page, { meta } from "./&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;";
        import Layout from "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../layouts/default&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))}&lt;/span&gt;&lt;span class="s2"&gt;";

        const page = (
          &amp;lt;MemoryRouter&amp;gt;
            &amp;lt;Layout language="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;
              &amp;lt;Page /&amp;gt;
            &amp;lt;/Layout&amp;gt;
          &amp;lt;/MemoryRouter&amp;gt;
        );

        export { page, meta };
      `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;sourcefile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;temp-page.jsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;resolveDir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;ReactRouter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-router-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;ReactRouterDom&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cannot require&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
    &lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
    &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;XMLHttpRequest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="err"&gt;{},
    &lt;/span&gt;&lt;span class="nc"&gt;XDomainRequest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="err"&gt;{},
    &lt;/span&gt;&lt;span class="nc"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;document&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sample&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;outputFiles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;runInContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;renderToString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;makeFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;outDir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;mkdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;recursive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;writeFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;makePage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;makeFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&amp;lt;div id="app"&amp;gt;.*&lt;/span&gt;&lt;span class="se"&gt;?&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;div&amp;gt;/&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;div id="app"&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/div&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dist&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;replacements&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;renderApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;outPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;makePage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;done&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;outPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;replacements&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;While the overall flow has remained the same, we now convert the page with some imports (e.g., &lt;code&gt;MemoryRouter&lt;/code&gt;) to a plain JavaScript script using the CommonJS module system. Therefore, the evaluation with the Node.js &lt;code&gt;vm&lt;/code&gt; module does not require &lt;code&gt;esm&lt;/code&gt; or &lt;code&gt;ts-node&lt;/code&gt; any more. Everything has been taken care of by esbuild.&lt;/p&gt;

&lt;p&gt;In the code above the actual esbuild usage is hidden in the &lt;code&gt;compile&lt;/code&gt; function, so let's see how we set it up:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;build&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;esbuild&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;codegenPlugin&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;esbuild-codegen-plugin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;basename&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;dist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;platform&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;entryPoints&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isBrowser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;platform&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;browser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;entryPoints&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;outdir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="na"&gt;write&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;bundle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;splitting&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isBrowser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;minify&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isBrowser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isBrowser&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;esm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;platform&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.jpg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.svg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.avif&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.webp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../..&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-router-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-dom/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nf"&gt;codegenPlugin&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dynamic-assets&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;build&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onResolve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/.*/&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lastIndexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;front&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;front&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dynamic-asset&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="p"&gt;};&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="p"&gt;});&lt;/span&gt;

          &lt;span class="nx"&gt;build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onLoad&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dynamic-asset&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/.*/&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`/assets/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`export default &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;
          &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;compile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Quite straight forward. The few things to note are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Again, the usage of &lt;code&gt;codegen&lt;/code&gt; is superb is there is literally a plugin for each bundler. So we can just use the codegen plugin for esbuild and we are covered here.&lt;/li&gt;
&lt;li&gt;The dynamic asset plugin that has been defined above looks within the files if the name and extension fits; if it does it will use the already generated one from Vite.&lt;/li&gt;
&lt;li&gt;We can reuse the &lt;code&gt;compile&lt;/code&gt; function not only for Node.js (the SSG part), but also for compiling some JS functions that run in the browser.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Especially the last point can be crucial. Right now this setup really moves the dynamic part (a SPA) to a fully static one. But we still have some interactive parts in there... So fully hydrating this thing - as we did beforehand - may not be good enough.&lt;/p&gt;

&lt;p&gt;But even with this more modern setup one thing was still from 2019: the overall performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lighthouse Issues
&lt;/h2&gt;

&lt;p&gt;In 2019 we still got a great Lighthouse score, but now it's mediocre at best. Lighthouse got a lot more pushy - especially regarding hydration scenarios as we have here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa3uj5f70t3y4v57p7cje.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa3uj5f70t3y4v57p7cje.png" alt="Initial lighthouse score"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The score summary is:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Desktop&lt;/th&gt;
&lt;th&gt;Mobile&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Score&lt;/td&gt;
&lt;td&gt;70&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best Practices&lt;/td&gt;
&lt;td&gt;81&lt;/td&gt;
&lt;td&gt;79&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;First Contentful Paint&lt;/td&gt;
&lt;td&gt;0.4 s&lt;/td&gt;
&lt;td&gt;1.7s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Largest Contentful Paint&lt;/td&gt;
&lt;td&gt;1.6 s&lt;/td&gt;
&lt;td&gt;8.4s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total Blocking Time&lt;/td&gt;
&lt;td&gt;0 ms&lt;/td&gt;
&lt;td&gt;20ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cumulative Layout Shift&lt;/td&gt;
&lt;td&gt;1.828&lt;/td&gt;
&lt;td&gt;1.899&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speed Index&lt;/td&gt;
&lt;td&gt;0.7s&lt;/td&gt;
&lt;td&gt;2.1s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There are some findings that seem rather optional, but nevertheless could be implemented rather quickly (or not at all):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easy: No CSP header (as this is just served as static content we could embed it easily in the HTML as &lt;code&gt;meta&lt;/code&gt; tag)&lt;/li&gt;
&lt;li&gt;Tedious: On mobile some images are served with a lower resolution (presumably going into the &lt;code&gt;picture&lt;/code&gt; tag with different &lt;code&gt;source&lt;/code&gt; elements to return the "right" resolution would fit)&lt;/li&gt;
&lt;li&gt;Impossible: Deprecated API used (&lt;code&gt;unload&lt;/code&gt; handler; use &lt;code&gt;pagehide&lt;/code&gt; event instead - actually we don't use this: the problem is coming/injected from a Chrome extension)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Naturally, the question is why the score is so low - and what we can do about it. Notably, we have a CLS (Cumulative Layout Shift) and a quite large LCP (Largest Contentful Paint).&lt;/p&gt;

&lt;h2&gt;
  
  
  Improvements
&lt;/h2&gt;

&lt;p&gt;The first thing to do is to lower the amount of work that the JS engine has to do. For this we needed to rethink our hydration strategy. The standard one from a React SPA is to hydrate everything. But this comes with a lot of overhead and a quite slow start.&lt;/p&gt;

&lt;p&gt;A much better approach would be to include an island architecture style here. Instead of hydrating everything in the beginning, we only hydrate parts - and only hydrate these parts when we need them (e.g., when they become visible).&lt;/p&gt;

&lt;p&gt;How can we do that? &lt;strong&gt;Time for magic&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let's consider the following code:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Testimonials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;container&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Testimonials&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;quote-carousel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TestimonialsSlides&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is the testimonials part of the homepage. Everything should be static - except the &lt;code&gt;TestimonialsSlides&lt;/code&gt;. This is a Carousel with some content. Everything is defined in React.&lt;/p&gt;

&lt;p&gt;What if we could just tell the system to hydrate it? Let's imagine we rewrite the code to look like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Testimonials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;container&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Testimonials&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;quote-carousel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;hydrate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;TestimonialsSlides&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TestimonialsSlides&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The only thing we changed is that we added a &lt;code&gt;data-hydrate&lt;/code&gt; attribute. Granted, this should be a string - but (surprise) we won't use the attribute anyway. We will actually change the attribute value at build-time.&lt;/p&gt;

&lt;p&gt;The architecture that we have in mind works as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvi3a5ywycsuzhinwj02o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvi3a5ywycsuzhinwj02o.png" alt="Architecture for the hydration replacements"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The build-time change in the SSG kernel module is an addition for the replacements:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createHash&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;crypto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getUniqueName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lastIndexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sha1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;matcher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/"data-&lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;hydrate|render|load&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;":&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;(\w&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;)[&lt;/span&gt;&lt;span class="sr"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\s]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;replacements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;matcher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lookup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;componentName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`var &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;componentName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lastIndexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;// &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../..&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getUniqueName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;replacements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`"data-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;": "/assets/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.js",`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;replacements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Nice! With this change we have a replacement of the attributes during the build process. We also identify the replacements to use them later on in one joint build process (such that they produce common chunks):&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;writeFile&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs/promises&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;compile&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./compile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;replacements&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="nx"&gt;dist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;platform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;browser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;entryPoints&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;replacements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;})),&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;outputFiles&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;writeFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;done&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The only thing missing is a replacement for the SPA script. The replacement should be able to work with the &lt;code&gt;data-hydrate&lt;/code&gt; attribute, which tells the website to hydrate a container with a specific file:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;integrate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getProps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-props&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;react&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reactDom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-dom/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;react&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reactDom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*[data-hydrate]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-hydrate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IntersectionObserver&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isIntersecting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;disconnect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
          &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(([{&lt;/span&gt; &lt;span class="nx"&gt;createElement&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;hydrateRoot&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;requestAnimationFrame&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;hydrateRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;getProps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;))));&lt;/span&gt;
          &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*[data-load]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-load&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(([{&lt;/span&gt; &lt;span class="nx"&gt;createElement&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;hydrateRoot&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;requestIdleCallback&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;hydrateRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;getProps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;))));&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*[data-render]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-render&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(([{&lt;/span&gt; &lt;span class="nx"&gt;createElement&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createRoot&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;createRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;getProps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readyState&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;loading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DOMContentLoaded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;integrate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;integrate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That is pretty much it! The great thing is that this script is so small that it can be inlined. Since we also know when / if we need replacements we'd only inline the script when we would need it (i.e., when we might hydrate).&lt;/p&gt;

&lt;p&gt;Finally, we externalized &lt;code&gt;react&lt;/code&gt; (and others), but we did not specify a replacement. As esbuild produces esm files those externals are placed as standard imports such as:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We would run into problems if such a thing is evaluated in the browser. The solution is to introduce an importmap in our page:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"importmap"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;imports&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://esm.sh/react@18.3.1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-dom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://esm.sh/react-dom@18.3.1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-dom/client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://esm.sh/react-dom@18.3.1/client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Note that the importmap is lazyly loaded anyway. So it will perform optimally out of the box.&lt;/p&gt;

&lt;p&gt;With everything in place we can look again at the lighthouse score.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnpdw0p2xm31m5uhi67y1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnpdw0p2xm31m5uhi67y1.png" alt="Lighthouse score after improvements"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The score summary is:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Desktop&lt;/th&gt;
&lt;th&gt;Mobile&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Score&lt;/td&gt;
&lt;td&gt;78&lt;/td&gt;
&lt;td&gt;65&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best Practices&lt;/td&gt;
&lt;td&gt;81&lt;/td&gt;
&lt;td&gt;79&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;First Contentful Paint&lt;/td&gt;
&lt;td&gt;0.6 s&lt;/td&gt;
&lt;td&gt;4.3s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Largest Contentful Paint&lt;/td&gt;
&lt;td&gt;1.3 s&lt;/td&gt;
&lt;td&gt;9.4s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total Blocking Time&lt;/td&gt;
&lt;td&gt;0 ms&lt;/td&gt;
&lt;td&gt;10ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cumulative Layout Shift&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speed Index&lt;/td&gt;
&lt;td&gt;0.6s&lt;/td&gt;
&lt;td&gt;4.3s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;While the score is already much better the LCP and overall speed index actually got worse. The reason the score is better is most notably that the CLS is now 0, which is great.&lt;/p&gt;

&lt;p&gt;So where did we go wrong?&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Touches
&lt;/h2&gt;

&lt;p&gt;While the SPA transition hurt our score, it did not hurt as much as badly hydrated components. One of these components is the main carousel, which is shown immediately.&lt;/p&gt;

&lt;p&gt;It turns out the carousel component was only made for SPAs. It dynamically computes the width and position of its slides based on the given content. The following diagram shows its working:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flxcevsn3a8kb9og8udpq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flxcevsn3a8kb9og8udpq.png" alt="Carousel component"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In short we have a container that gets the dimensions of the component. Inside the container we use a content element that has the width of the container multiplied by the number of slides + 2. We add two as we also introduce duplicates for the first and last slide. This way, we can have the experience of a real carousel. From the last slide you can keep on swiping right to get to the first slide and vice versa. Essentially, this allows you to keep scrolling in one direction.&lt;/p&gt;

&lt;p&gt;What can we do to improve the code here?&lt;/p&gt;

&lt;p&gt;Instead of relying on the runtime to set &lt;code&gt;style&lt;/code&gt; properties we return a pre-computed &lt;code&gt;style&lt;/code&gt; object. This way, we only change dynamic properties when a scrol operation starts.&lt;/p&gt;

&lt;p&gt;Originally, the code had a function like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updateOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;parentElement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;transform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;translateX(0)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;transition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;desired&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;active&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;active&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;desired&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dist&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;desired&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;active&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shift&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pref&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;transition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;smooth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;transform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`translateX(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;%)`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isNaN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;transform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`translateX(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px)`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;transition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;elastic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`-&lt;/span&gt;&lt;span class="p"&gt;${(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;active&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;%`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now we move to:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updateOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;transform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;translateX(0)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;transition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;desired&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;active&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shift&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getShift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;active&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;desired&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;transition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;smooth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;transform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`translateX(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;%)`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isNaN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;transform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`translateX(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px)`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;transition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;elastic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The new &lt;code&gt;getShift&lt;/code&gt; function is also much improved:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getShift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;desired&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;desired&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;active&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;desired&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;active&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;pref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;diff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;active&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;desired&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This results in a better UX while also improving the story for SSG / SSR.&lt;/p&gt;

&lt;p&gt;Besides the work on the carousel component we also optimized the images and spend some time on content cleanup. Nothing dramatic - just little wins here and there.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdofubqc7suste1d298nq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdofubqc7suste1d298nq.png" alt="Final lighthouse score"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The score summary is:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Desktop&lt;/th&gt;
&lt;th&gt;Mobile&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Score&lt;/td&gt;
&lt;td&gt;99&lt;/td&gt;
&lt;td&gt;87&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best Practices&lt;/td&gt;
&lt;td&gt;78&lt;/td&gt;
&lt;td&gt;75&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;First Contentful Paint&lt;/td&gt;
&lt;td&gt;0.6 s&lt;/td&gt;
&lt;td&gt;2.6s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Largest Contentful Paint&lt;/td&gt;
&lt;td&gt;0.8 s&lt;/td&gt;
&lt;td&gt;3.4s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total Blocking Time&lt;/td&gt;
&lt;td&gt;0 ms&lt;/td&gt;
&lt;td&gt;10ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cumulative Layout Shift&lt;/td&gt;
&lt;td&gt;0.009&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speed Index&lt;/td&gt;
&lt;td&gt;0.6s&lt;/td&gt;
&lt;td&gt;2.6s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is it! Wonderful that such a "little" change in a single component can have such a drastic outcome. But in the end it's all about the details.&lt;/p&gt;

&lt;p&gt;While every metric now looks good the best practices got a bit worse. Why? Because we added a small video in form of a YouTube embed (&lt;code&gt;iframe&lt;/code&gt;) into the homepage. As YouTube brings quite some cookies and other things Lighthouse is not really happy with the third-party content. So we can actually ignore this.&lt;/p&gt;

&lt;p&gt;As wanted to be in the 90s rating this is certainly a success and as desired.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Overall, we kept the codebase stable and just gave the whole source code a bit of a makeover. This was sufficient to reach the next level of DX and performance.&lt;/p&gt;

&lt;p&gt;As next step we'll modernize some of our content and re-introduce the SPA transition by hijacking internal links; loading an HTML fragment during a page transition. We'll potentially also replace the importmap with an integrated bundle, using Preact in compat mode as a replacement.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>performance</category>
      <category>javascript</category>
    </item>
    <item>
      <title>🧠 Don't Miss These 50 Articles</title>
      <dc:creator>Florian Rappl</dc:creator>
      <pubDate>Mon, 26 Aug 2024 07:54:56 +0000</pubDate>
      <link>https://forem.com/florianrappl/dont-miss-these-50-articles-5dg4</link>
      <guid>https://forem.com/florianrappl/dont-miss-these-50-articles-5dg4</guid>
      <description>&lt;p&gt;&lt;em&gt;&lt;a href="https://www.freepik.com/free-vector/gradient-step-illustration_37443122.htm#fromView=search&amp;amp;page=1&amp;amp;position=9&amp;amp;uuid=034a1fce-8fa5-40fe-9832-045f25551c3a" rel="noopener noreferrer"&gt;Image by freepik&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This year I started a new series on &lt;a href="https://www.linkedin.com/in/florian-rappl/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; - "Advanced Links for Frontend". Each issue has 10 links to outstanding posts / articles. This bundle contains the links from the last 5 issues (issue 46 to issue 50).&lt;/p&gt;

&lt;p&gt;I hope you enjoy this collection. Let me know in the comments which of these articles is your favorite (and why).&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 46
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Garbage collection and closures&lt;/strong&gt; (&lt;a href="https://jakearchibald.com/2024/garbage-collection-and-closures/" rel="noopener noreferrer"&gt;https://jakearchibald.com/2024/garbage-collection-and-closures/&lt;/a&gt;) by Jake Archibald&lt;br&gt;
Weak references for the win. Honestly, finding memory leaks is always tricky - even you find the source fast; getting rid of it can be complex.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Look at What's Coming to PHP 8.4&lt;/strong&gt; (&lt;a href="https://laravel-news.com/php-8-4-0" rel="noopener noreferrer"&gt;https://laravel-news.com/php-8-4-0&lt;/a&gt;) by Paul Redmond&lt;br&gt;
The last thing I'd do is bet against PHP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This month in Servo: console logging, parallel tables, OpenXR, and more!&lt;/strong&gt; (&lt;a href="https://servo.org/blog/2024/07/31/this-month-in-servo/" rel="noopener noreferrer"&gt;https://servo.org/blog/2024/07/31/this-month-in-servo/&lt;/a&gt;) by Servo&lt;br&gt;
Servo is one of the main reasons Rust exists today - a browser engine that is fast and transportable. It's great to see them back and continuing to do well!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to Get the Width/Height of Any Element in Only CSS&lt;/strong&gt; (&lt;a href="https://frontendmasters.com/blog/how-to-get-the-width-height-of-any-element-in-only-css/" rel="noopener noreferrer"&gt;https://frontendmasters.com/blog/how-to-get-the-width-height-of-any-element-in-only-css/&lt;/a&gt;) by Temani Afif&lt;br&gt;
This is getting crazy. Previously this was thought as impossible as CSS is used to compute those values, now that Chromium has full support we are most likely to see it across all browsers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Styling Tables the Modern CSS Way&lt;/strong&gt; (&lt;a href="https://piccalil.li/blog/styling-tables-the-modern-css-way/" rel="noopener noreferrer"&gt;https://piccalil.li/blog/styling-tables-the-modern-css-way/&lt;/a&gt;) by Michelle Barker&lt;br&gt;
Every once in a while somebody reminds me that tables are still a thing. They are - and styling them properly is actually required to make full use of them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Web Styles in Native Apps&lt;/strong&gt; (&lt;a href="https://www.telerik.com/blogs/web-styles-native-apps" rel="noopener noreferrer"&gt;https://www.telerik.com/blogs/web-styles-native-apps&lt;/a&gt;) by Sam Basu&lt;br&gt;
Was not really sure what to expect in here, but I got happy once I saw XAML. Quite cool article if you work in the Blazor / MAUI space.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2024 Developer Survey Results&lt;/strong&gt; (&lt;a href="https://survey.stackoverflow.co/2024" rel="noopener noreferrer"&gt;https://survey.stackoverflow.co/2024&lt;/a&gt;) by StackOverflow&lt;br&gt;
Pretty much no surprises here. However, that reminds me that we may be should start another micro frontend survey?! It's about time...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Battle of the Asyncs&lt;/strong&gt; (&lt;a href="https://www.brenelz.com/posts/battle-of-the-asyncs/" rel="noopener noreferrer"&gt;https://www.brenelz.com/posts/battle-of-the-asyncs/&lt;/a&gt;) by Brenley Dueck&lt;br&gt;
I missed the battle in this one, but generally a good comparison of the different philosophies behind Solid and React. There is more to it, but this is just a solid point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Please Stop Using Barrel Files&lt;/strong&gt; (&lt;a href="https://tkdodo.eu/blog/please-stop-using-barrel-files" rel="noopener noreferrer"&gt;https://tkdodo.eu/blog/please-stop-using-barrel-files&lt;/a&gt;) by Dominik Dorfmeister&lt;br&gt;
I agree up to some degree. In general if you use barrel files you should also treat the folders / barrels like its own library; i.e., think of it as a dependency and always visualize how the dependency graph flows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What we (Deno) got wrong about HTTP imports&lt;/strong&gt; (&lt;a href="https://deno.com/blog/http-imports" rel="noopener noreferrer"&gt;https://deno.com/blog/http-imports&lt;/a&gt;) by Ryan Dahl&lt;br&gt;
One of the longer ads for JSR. While I am still positive about the JSR I also see some drawbacks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 47
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Plain Vanilla&lt;/strong&gt; (&lt;a href="https://plainvanillaweb.com/" rel="noopener noreferrer"&gt;https://plainvanillaweb.com/&lt;/a&gt;) by Joeri Sebrechts&lt;br&gt;
A nice collection of starters and ideas for going fully vanilla. Be aware that following this you might end up with your own framework.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A different way to think about typescript&lt;/strong&gt; (&lt;a href="https://www.rob.directory/blog/a-different-way-to-think-about-typescript" rel="noopener noreferrer"&gt;https://www.rob.directory/blog/a-different-way-to-think-about-typescript&lt;/a&gt;) by Robby Pruzan&lt;br&gt;
TypeScript is like a strict librarian who insists on organizing infinite sets of values, just so you can avoid typos in your code!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Google handles JavaScript throughout the indexing process&lt;/strong&gt; (&lt;a href="https://vercel.com/blog/how-google-handles-javascript-throughout-the-indexing-process" rel="noopener noreferrer"&gt;https://vercel.com/blog/how-google-handles-javascript-throughout-the-indexing-process&lt;/a&gt;) by Ryan Siddle and Malte Ubl&lt;br&gt;
I'm glad this got out. I'm tired of telling everyone that you don't need SSR to be seen by Google.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Patterns for Memory Efficient DOM Manipulation with Modern Vanilla JavaScript&lt;/strong&gt; (&lt;a href="https://frontendmasters.com/blog/patterns-for-memory-efficient-dom-manipulation/" rel="noopener noreferrer"&gt;https://frontendmasters.com/blog/patterns-for-memory-efficient-dom-manipulation/&lt;/a&gt;) by Marc Grabanski&lt;br&gt;
Spot the pattern? All vanilla. Knowing your DOM API is key.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benchmarking AWS Lambda Cold Starts Across JavaScript Runtimes&lt;/strong&gt; (&lt;a href="https://deno.com/blog/aws-lambda-coldstart-benchmarks" rel="noopener noreferrer"&gt;https://deno.com/blog/aws-lambda-coldstart-benchmarks&lt;/a&gt;) by Andy Jiang and Igor Zinkovsky&lt;br&gt;
Alright, so Deno is actually quite fast - but what's more important is that Hono is super (even more than Express) lightweight.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nx 19.5 is here! Stackblitz, Bun, Incremental Builds for Vite, Gradle Test Atomizer&lt;/strong&gt; (&lt;a href="https://nx.dev/blog/nx-19-5-adds-stackblitz-new-features-and-more" rel="noopener noreferrer"&gt;https://nx.dev/blog/nx-19-5-adds-stackblitz-new-features-and-more&lt;/a&gt;) by Zack DeRose&lt;br&gt;
Well that's a nice feature set! Incremental builds are super slick, so very happy with this one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CSS Spring Easing Generator&lt;/strong&gt; (&lt;a href="https://www.kvin.me/css-springs" rel="noopener noreferrer"&gt;https://www.kvin.me/css-springs&lt;/a&gt;) by Kevin Grajeda&lt;br&gt;
The missing piece for crucial CSS snippet tools collection. Wait...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common Sense Refactoring of a Messy React Component&lt;/strong&gt; (&lt;a href="https://alexkondov.com/refactoring-a-messy-react-component/" rel="noopener noreferrer"&gt;https://alexkondov.com/refactoring-a-messy-react-component/&lt;/a&gt;) by Alex Kondov&lt;br&gt;
Hey, I'm still missing the final outcome! Spoiler: Instead of one large file we now have 3 new dependencies and 15 files. Just kidding!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An Alpine &amp;amp; Tailwind UI Library&lt;/strong&gt; (&lt;a href="https://devdojo.com/pines" rel="noopener noreferrer"&gt;https://devdojo.com/pines&lt;/a&gt;) by Tony Lea et al.&lt;br&gt;
Looks quite nice, but I wonder if copying over so much code is really efficient if you want to reuse these components. For single use-cases I think this is wonderful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;React Compiler, How Does It Work? 4 - SSA Transformation&lt;/strong&gt; (&lt;a href="https://yongseok.me/blog/en/react_compiler_4/" rel="noopener noreferrer"&gt;https://yongseok.me/blog/en/react_compiler_4/&lt;/a&gt;) by YongSeok Jang&lt;br&gt;
The techniques presented in the article also play a role in many other parsers / compilers / transpilers. Super cool!&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 48
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Announcing Official Puppeteer Support for Firefox&lt;/strong&gt; (&lt;a href="https://hacks.mozilla.org/2024/08/puppeteer-support-for-firefox/" rel="noopener noreferrer"&gt;https://hacks.mozilla.org/2024/08/puppeteer-support-for-firefox/&lt;/a&gt;) by James Graham, Henrik Skupin, Julian Descottes, Alexandra Borovova&lt;br&gt;
That was about time - quite happy that's here. Still, I'll keep on using Playwright.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A tiny utility to build JSON schema types&lt;/strong&gt; (&lt;a href="https://github.com/lukeed/tschema" rel="noopener noreferrer"&gt;https://github.com/lukeed/tschema&lt;/a&gt;) by Luke Edwards&lt;br&gt;
Super useful - well done! Finally I only need to define it once.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Effect Best Practices&lt;/strong&gt; (&lt;a href="https://ethanniser.dev/blog/effect-best-practices/" rel="noopener noreferrer"&gt;https://ethanniser.dev/blog/effect-best-practices/&lt;/a&gt;) by Ethan Niser&lt;br&gt;
Using the useful Effect utility lib? This post should be on your radar.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Introducing XState Store&lt;/strong&gt; (&lt;a href="https://tkdodo.eu/blog/introducing-x-state-store" rel="noopener noreferrer"&gt;https://tkdodo.eu/blog/introducing-x-state-store&lt;/a&gt;) by Dominik Dorfmeister&lt;br&gt;
Dominik keeps on delivering great content! It's half the size of Zustand yet seems very comparable feature-wise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gradient Generator&lt;/strong&gt; (&lt;a href="https://www.learnui.design/tools/gradient-generator.html" rel="noopener noreferrer"&gt;https://www.learnui.design/tools/gradient-generator.html&lt;/a&gt;) by Kennedy Design&lt;br&gt;
Last time we had an awesome easing generator - this time it's about gradients.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Integrating Blazor with Existing .NET Web Apps&lt;/strong&gt; (&lt;a href="https://visualstudiomagazine.com/Articles/2024/08/07/Integrating-Blazor-with-Existing-,-d-,NET-Web-Apps.aspx" rel="noopener noreferrer"&gt;https://visualstudiomagazine.com/Articles/2024/08/07/Integrating-Blazor-with-Existing-,-d-,NET-Web-Apps.aspx&lt;/a&gt;) by David Ramel&lt;br&gt;
Very nice interview for the session scheduled at Live!360 conference in Orlando. Would be even better if micro frontends are mentioned ;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's Time To Talk About "CSS5"&lt;/strong&gt; (&lt;a href="https://www.smashingmagazine.com/2024/08/time-to-talk-about-css5/" rel="noopener noreferrer"&gt;https://www.smashingmagazine.com/2024/08/time-to-talk-about-css5/&lt;/a&gt;) by Brecht De Ruyte&lt;br&gt;
I'm listening. BTW the last full spec of CSS was 2.1 - since then everything is divided into modules, which have their own level. CSS3 was the first to just be an aggregate of the module levels.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Google Angular Lead Sees Convergence in JavaScript Frameworks&lt;/strong&gt; (&lt;a href="https://thenewstack.io/google-angular-lead-sees-convergence-in-javascript-frameworks/" rel="noopener noreferrer"&gt;https://thenewstack.io/google-angular-lead-sees-convergence-in-javascript-frameworks/&lt;/a&gt;) by Loraine Lawson&lt;br&gt;
I think this is a bit misleading. Just because React now has a compiler does not mean it's converging to Angular...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Great npm Garbage Patch&lt;/strong&gt; (&lt;a href="https://blog.phylum.io/the-great-npm-garbage-patch/" rel="noopener noreferrer"&gt;https://blog.phylum.io/the-great-npm-garbage-patch/&lt;/a&gt;) by Phylum Research Team&lt;br&gt;
Being in touch with Tea protocol myself I am not surprised. It's, unfortunately, essentially crypto garbage. Happy that someone is aware of the problem and reporting the issues for improvement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Sneaky Costs of Scaling Serverless&lt;/strong&gt; (&lt;a href="https://www.zachleat.com/web/serverless-cost/" rel="noopener noreferrer"&gt;https://www.zachleat.com/web/serverless-cost/&lt;/a&gt;) by Zach Leatherman&lt;br&gt;
Spoiler: Serverless can lead to (unnecessary) massive bills if not used correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 49
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Do Quests, Not Goals&lt;/strong&gt; (&lt;a href="https://www.raptitude.com/2024/08/do-quests-not-goals/" rel="noopener noreferrer"&gt;https://www.raptitude.com/2024/08/do-quests-not-goals/&lt;/a&gt;) by David Cain&lt;br&gt;
Right now I am not doing anything besides hiking, swimming, and enjoying the mountains.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zen Browser&lt;/strong&gt; (&lt;a href="https://www.zen-browser.app/" rel="noopener noreferrer"&gt;https://www.zen-browser.app/&lt;/a&gt;) by Zen&lt;br&gt;
This is what Firefox feels to me. But maybe worth giving it a try, too?!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tips from 8 months of TanStack/Router in production&lt;/strong&gt; (&lt;a href="https://swizec.com/blog/tips-from-8-months-of-tan-stack-router-in-production/" rel="noopener noreferrer"&gt;https://swizec.com/blog/tips-from-8-months-of-tan-stack-router-in-production/&lt;/a&gt;) by Swizec Teller&lt;br&gt;
I still miss the point of using something besides React Router, but I guess that's just a sign of me getting old.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Parallel DOM&lt;/strong&gt; (&lt;a href="https://www.pdom.dev/#how-it-works" rel="noopener noreferrer"&gt;https://www.pdom.dev/#how-it-works&lt;/a&gt;) by Ashish Shubham&lt;br&gt;
Unfortunately the demos don't work in Firefox - but otherwise looks great if you think about distributing rendering tasks!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An approach to optimizing TypeScript type checking performance&lt;/strong&gt; (&lt;a href="https://www.edgedb.com/blog/an-approach-to-optimizing-typescript-type-checking-performance" rel="noopener noreferrer"&gt;https://www.edgedb.com/blog/an-approach-to-optimizing-typescript-type-checking-performance&lt;/a&gt;) by Scott Trinh&lt;br&gt;
Especially check out the general advice section on how to write better performing types.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Optimizing SPA load times with async chunks preloading&lt;/strong&gt; (&lt;a href="https://mmazzarolo.com/blog/2024-08-13-async-chunk-preloading-on-load/" rel="noopener noreferrer"&gt;https://mmazzarolo.com/blog/2024-08-13-async-chunk-preloading-on-load/&lt;/a&gt;) by Mazzarolo Matteo&lt;br&gt;
I'd argue that bundle splitting is great, but instead of just blindly preloading everything you'd only preload parts before they become relevant, e.g., when certain areas are visible or focused.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerendering with Preset Vite&lt;/strong&gt; (&lt;a href="https://preactjs.com/blog/prerendering-preset-vite/" rel="noopener noreferrer"&gt;https://preactjs.com/blog/prerendering-preset-vite/&lt;/a&gt;) by Ryan Christian&lt;br&gt;
This is definitely a useful plugin. Since you can mostly also just alias / replace React by Preact it could be a great way out for simpler pages to avoid requiring JavaScript.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Node.js Takes Steps Towards Removing Corepack&lt;/strong&gt; (&lt;a href="https://socket.dev/blog/node-js-takes-steps-towards-removing-corepack" rel="noopener noreferrer"&gt;https://socket.dev/blog/node-js-takes-steps-towards-removing-corepack&lt;/a&gt;) by Sarah Gooding&lt;br&gt;
Personally, I think it would be better to remove corepack and let it evolve independently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A case for vanilla JSX&lt;/strong&gt; (&lt;a href="https://vanillajsx.com/" rel="noopener noreferrer"&gt;https://vanillajsx.com/&lt;/a&gt;) by sdegutis&lt;br&gt;
There is a great debate ongoing in the WICG Web Components GitHub repository that might actually benefit from native JSX (&lt;a href="https://github.com/WICG/webcomponents/issues/1069" rel="noopener noreferrer"&gt;https://github.com/WICG/webcomponents/issues/1069&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;20 years since open source release, here comes Ruby on Rails 7.2 with JIT compiler and more&lt;/strong&gt; (&lt;a href="https://devclass.com/2024/08/13/20-years-since-open-source-release-here-comes-ruby-on-rails-7-2-with-jit-compiler-and-more/" rel="noopener noreferrer"&gt;https://devclass.com/2024/08/13/20-years-since-open-source-release-here-comes-ruby-on-rails-7-2-with-jit-compiler-and-more/&lt;/a&gt;) by Tim Anderson&lt;br&gt;
20 years ago I found Ruby. Two years later I started using Rails, but even though I then headed in a different direction I still think this is one of the best ecosystems out there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 50
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Optimizing React Applications for Maximum Performance&lt;/strong&gt; (&lt;a href="https://dev.to/surajondev/optimizing-react-applications-for-maximum-performance-5epm"&gt;https://dev.to/surajondev/optimizing-react-applications-for-maximum-performance-5epm&lt;/a&gt;) by &lt;a class="mentioned-user" href="https://dev.to/surajondev"&gt;@surajondev&lt;/a&gt; &lt;br&gt;
Honestly, there is a bit more to it, but following these points will give you a great starting point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ASPNetCore Angular SPA application with SEO friendly (SSR) Title and Meta tags updates&lt;/strong&gt; (&lt;a href="https://medium.com/@haykflexgrigoryan/aspnetcore-angular-spa-application-with-seo-friendly-ssr-title-and-meta-tags-updates-bcef5f75b6ad" rel="noopener noreferrer"&gt;https://medium.com/@haykflexgrigoryan/aspnetcore-angular-spa-application-with-seo-friendly-ssr-title-and-meta-tags-updates-bcef5f75b6ad&lt;/a&gt;) by Hakob Grigoryan&lt;br&gt;
Using AngleSharp to optimize an Angular app for SEO? Count me in!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Building Micro-frontends using Blazor and Piral Framework⚡&lt;/strong&gt; (&lt;a href="https://wdevon99.medium.com/building-micro-frontends-using-blazor-and-piral-framework-c38c5426ccee" rel="noopener noreferrer"&gt;https://wdevon99.medium.com/building-micro-frontends-using-blazor-and-piral-framework-c38c5426ccee&lt;/a&gt;) by Devon Wijesinghe&lt;br&gt;
Very well written and with a great demo project that you can just use as a starting point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bye Bye, Try-Catch Blocks: Meet JavaScript's Safe Assignment Operator Proposal😉&lt;/strong&gt; (&lt;a href="https://dev.to/dharamgfx/bye-bye-try-catch-blocks-meet-javascripts-safe-assignment-operator-proposal-1j7"&gt;https://dev.to/dharamgfx/bye-bye-try-catch-blocks-meet-javascripts-safe-assignment-operator-proposal-1j7&lt;/a&gt;) by &lt;a class="mentioned-user" href="https://dev.to/dharamgfx"&gt;@dharamgfx&lt;/a&gt; &lt;br&gt;
This is not yet finalized - but sometimes having the discussion earlier is better than later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Regexes Got Good: The History And Future Of Regular Expressions In JavaScript&lt;/strong&gt; (&lt;a href="https://www.smashingmagazine.com/2024/08/history-future-regular-expressions-javascript/" rel="noopener noreferrer"&gt;https://www.smashingmagazine.com/2024/08/history-future-regular-expressions-javascript/&lt;/a&gt;) by Steven Levithan&lt;br&gt;
This is finalized. While regular expressions in JS will never reach the level of Perl, they are certainly quite decent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;From React to Effect&lt;/strong&gt; (&lt;a href="https://effect.website/blog/from-react-to-effect" rel="noopener noreferrer"&gt;https://effect.website/blog/from-react-to-effect&lt;/a&gt;) by Michael Arnaldi&lt;br&gt;
I was curious at the title, but then it hit me... should have rather been called "Effect for React developers".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Introducing Nuxt Scripts&lt;/strong&gt; (&lt;a href="https://nuxt.com/blog/nuxt-scripts" rel="noopener noreferrer"&gt;https://nuxt.com/blog/nuxt-scripts&lt;/a&gt;) by Harlan Wilton&lt;br&gt;
Sounds interesting, but I wonder if this could (or should) be extended beyond Nuxt.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;spatial compute&lt;/strong&gt; (&lt;a href="https://sunilpai.dev/posts/spatial-compute/" rel="noopener noreferrer"&gt;https://sunilpai.dev/posts/spatial-compute/&lt;/a&gt;) by Sunil Pai&lt;br&gt;
Have we already conquered temporal compute?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JS Dates Are About to Be Fixed&lt;/strong&gt; (&lt;a href="https://docs.timetime.in/blog/js-dates-finally-fixed/" rel="noopener noreferrer"&gt;https://docs.timetime.in/blog/js-dates-finally-fixed/&lt;/a&gt;) by Iago Lastra&lt;br&gt;
When did I hear that the last time?!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Good Refactoring vs Bad Refactoring&lt;/strong&gt; (&lt;a href="https://www.builder.io/blog/good-vs-bad-refactoring" rel="noopener noreferrer"&gt;https://www.builder.io/blog/good-vs-bad-refactoring&lt;/a&gt;) by Steve Sewell&lt;br&gt;
We've all been there... Most important part: Understand the code, and make sure previously working code can be verified to still be working.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;These are all outstanding articles by masterful authors. I enjoyed reading them all - I hope you did find something in there, too.&lt;/p&gt;

&lt;p&gt;👉 Follow me on &lt;a href="https://www.linkedin.com/in/florian-rappl/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://twitter.com/FlorianRappl" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, or here for more to come.&lt;/p&gt;

&lt;p&gt;🙏 Thanks to all the authors and contributors for their hard work!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>node</category>
      <category>frontend</category>
    </item>
    <item>
      <title>🤯 Migration: Completed</title>
      <dc:creator>Florian Rappl</dc:creator>
      <pubDate>Tue, 06 Aug 2024 13:20:47 +0000</pubDate>
      <link>https://forem.com/florianrappl/migration-completed-2f97</link>
      <guid>https://forem.com/florianrappl/migration-completed-2f97</guid>
      <description>&lt;p&gt;In the previous four articles (&lt;a href="https://dev.to/florianrappl/migration-from-classic-hosting-to-serverless-3pkh"&gt;Migration from Classic Hosting to Serverless&lt;/a&gt;, &lt;a href="https://dev.to/florianrappl/migration-of-a-multiplayer-game-from-hosted-to-serverless-2c6o"&gt;Migration of a Multiplayer Game from Hosted to Serverless&lt;/a&gt;, &lt;a href="https://dev.to/florianrappl/migration-of-a-dynamic-website-to-a-static-website-iaj"&gt;Migration of a Dynamic Website to a Static Website&lt;/a&gt;, and &lt;a href="https://dev.to/florianrappl/migration-of-mario-5-to-serverless-b00"&gt;Migration of Mario 5 to Serverless &lt;/a&gt;) I've introduced you to my plan of migrating away from my dedicated server to a fully serverless infrastructure.&lt;/p&gt;

&lt;p&gt;A little bit over 8 months I finished the migration (it's been a while!) of my website &lt;a href="https://florian-rappl.de" rel="noopener noreferrer"&gt;florian-rappl.de&lt;/a&gt;. So, now it's time to reveal how it went and what's improved (or even got worse).&lt;/p&gt;

&lt;p&gt;Before I go into details - let's recap a bit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Migrate?!
&lt;/h2&gt;

&lt;p&gt;Quick recap: What did I expect from this migration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A more clean code base (finally I can clean up my stuff, maybe remove something and modernize some other parts)&lt;/li&gt;
&lt;li&gt;No more FTP or messy / unclear deployments - everything should be handled by CI/CD pipelines&lt;/li&gt;
&lt;li&gt;Cost reduction; sounds weird, but the last thing I want to have is a cost increase (today it's about 30 € per month for the hosting and my goal is to bring this below or close to 10 € - note: I pay much more for domains and these costs are not included here as they will remain the same).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is a bit of background to this: Having my own dedicated server is something I was initially was happy about, however, over all the years the burden of properly maintaining this machine was a bit too high. I have quite some things on my plate and dealing with the (software-side) of a dedicated server was always on the bottom part of my ToDo list.&lt;/p&gt;

&lt;p&gt;So, here we are!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Long Way
&lt;/h2&gt;

&lt;p&gt;Surely, this is "just" a little homepage, but as you can see from the previous articles there are quite some things I'd like to keep working. Overall, the whole migration was prepared all along - with a quick brainstorming first.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbw365s8t6wndf0raubpo.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbw365s8t6wndf0raubpo.jpg" alt="Preparation for the Cloud Migration" width="800" height="1126"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This identified what needs to be migrated and how. So having arrived at the end it's time to look at my homepage and what kind of migration it needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Final Piece - My Homepage
&lt;/h2&gt;

&lt;p&gt;In a way this website belongs in a museum. It's out there since 2008 and the inner core never really changed. Surely, there have been some migrations (e.g., from ASP.NET Core MVC to MVC 3 to MVC 4), but all in all the code never really changed.&lt;/p&gt;

&lt;p&gt;At the core of the website is a custom CMS that allows me to write, edit, and publish articles on the website. An article may look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft1wyyynqbqb70rwrjbsg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft1wyyynqbqb70rwrjbsg.png" alt="Article on the website" width="800" height="798"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While the content is dynamically rendered, other relevant parts of the page (such as the suggestions or tags) are retrieved in relation to the shown article.&lt;/p&gt;

&lt;p&gt;The CMS is fully embedded in the website, i.e., the website is also rendering its own admin area that allows to perform all the administrative tasks.&lt;/p&gt;

&lt;p&gt;All the data is kept in a MySQL database. There are 28 tables for the whole website - with some tables (such as membership etc.) not being necessary any more. Most of the data is actually stored in the analytics tables, which are then used in the administrative area to display the usage charts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo8cawe871xcdknt4rumx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo8cawe871xcdknt4rumx.png" alt="Table Analysis for the Cloud Migration" width="800" height="651"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The red lines have been used by me to indicate what was already successfully migrated.&lt;/p&gt;

&lt;p&gt;So let's see how the migration process was done in detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migration Process
&lt;/h2&gt;

&lt;p&gt;First, I identified the general architecture. For me it was clear that in the long run I want to migrate the page to something more static, e.g., based on Astro. But right now, I certainly don't have the time to look over this and actually do it.&lt;/p&gt;

&lt;p&gt;As the website is an ASP.NET MVC 4 project that is certainly incompatible with ASP.NET Core I was in a bit of pickle. It was obvious that I cannot use something really cheap (such a Linux App service or Azure Container Instance). I still needed to run on Windows. But on the other hand, I did not want to have a full virtual machine (too expensive, and too much maintenance required).&lt;/p&gt;

&lt;p&gt;In the end, I went for using an Azure App Service with a rather cheap plan (that is still fully covered by my monthly Azure allowance). As plan I've taken &lt;strong&gt;B1&lt;/strong&gt;, which is around 30 € per month. Still, this plan already comes with support for custom domains and full-time operation.&lt;/p&gt;

&lt;p&gt;Once I deployed the page I've seen that the performance was just superb. &lt;em&gt;Page generation took **0ms&lt;/em&gt;&lt;em&gt;!&lt;/em&gt; Well, if things are too good to be true - they usually are not true. So let's investigate...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw9u098mhy87tnhn63w3c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw9u098mhy87tnhn63w3c.png" alt="Broken Timing Module" width="800" height="594"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The whole logic is triggered from a certain &lt;code&gt;IHttpModule&lt;/code&gt; called &lt;code&gt;TimingModule&lt;/code&gt;. The code is like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;FlorianRappl&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Diagnostics&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Web&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TimingModule&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IHttpModule&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpApplication&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BeginRequest&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;OnBeginRequest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EndRequest&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;OnEndRequest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Dispose&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnBeginRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventArgs&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;stopwatch&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Stopwatch&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;stopwatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;HttpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Stopwatch"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stopwatch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnEndRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EventArgs&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;stopwatch&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HttpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Stopwatch"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;Stopwatch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stopwatch&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;stopwatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In short, when a request begins we start a stopwatch. Once it ends - we just stop the stopwatch. We place the result in the current &lt;code&gt;HttpContext&lt;/code&gt;. This way, we can access it within our view and render the page with the stop watch timing.&lt;/p&gt;

&lt;p&gt;The problem now occurs as the &lt;code&gt;system.web&lt;/code&gt; configuration of the &lt;code&gt;Web.config&lt;/code&gt; file is not fully considered when running in an Azure App Service. This is a consequence of the App Service running its own runtime - so we don't bring the full runtime. Therefore, only configuration steps &lt;em&gt;after&lt;/em&gt; the runtime initialized can be considered.&lt;/p&gt;

&lt;p&gt;Consequently, the following sections &lt;strong&gt;can be removed&lt;/strong&gt; from the &lt;code&gt;Web.config&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;system.web&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;httpModules&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"TimingModule"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"FlorianRappl.Modules.TimingModule, FlorianRappl"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/httpModules&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- rest as-is --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/system.web&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;system.webServer&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;modules&lt;/span&gt; &lt;span class="na"&gt;runAllManagedModulesForAllRequests=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"TimingModule"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"FlorianRappl.Modules.TimingModule, FlorianRappl"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/modules&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- rest as-is --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/system.webServer&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- rest as-is --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But what to add for bringing back the timing module? Introducing... the &lt;code&gt;PreApplicationStartCode&lt;/code&gt;. Just introduce a class like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;FlorianRappl&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Web&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PreApplicationStartCode&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;HttpApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RegisterModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimingModule&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can have access to the startup code of the runtime. We use it to register the &lt;code&gt;TimingModule&lt;/code&gt; in the application.&lt;/p&gt;

&lt;p&gt;With this everything is in ship-shape:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn9ytbfzqxbza85u5bwo4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn9ytbfzqxbza85u5bwo4.png" alt="Fixed Timing Module" width="800" height="594"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that this is working it's time to look at some performance improvements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Improvements
&lt;/h2&gt;

&lt;p&gt;You may wonder: Why is it slower than beforehand? Well, there are many reasons. For once, we now are running in a shared environment. Beforehand, we had a dedicated server.&lt;/p&gt;

&lt;p&gt;However, certainly the larger impact comes from the database. Beforehand, we have been using a MySQL system running on the same machine (i.e., short travel distance), now we run on very cheap Azure Table Storage (i.e., longer travel distance, less query throughput).&lt;/p&gt;

&lt;p&gt;Specifically, there are many unnecessary queries running. One thing we can do to improve this is to introduce some caching. Specifically, we can cache the article listings (not the articles themselves) and the tags (they are often correlated and need to be used for coming up with suggestions).&lt;/p&gt;

&lt;p&gt;The effect of caching can be seen immediately.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsmb0rp0jac00xxk8nubg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsmb0rp0jac00xxk8nubg.png" alt="Performance Evaluation with Caching" width="800" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But one thing was still missing... I realized that there is a certain spike in response times when the long polling endpoint is called. In the end, it turned out that ASP.NET MVC is only allowing a single session to retrieve data at a time. If more requests come in from the same session then these requests need to wait.&lt;/p&gt;

&lt;p&gt;There is a simple way out of this trouble: Declare the &lt;code&gt;SessionState&lt;/code&gt; as &lt;code&gt;ReadOnly&lt;/code&gt;. This way, we cannot modify the session associated with the request, but we therefore also don't need to wait to avoid any race condition.&lt;/p&gt;

&lt;p&gt;This can look like this (here, all endpoints of the controller are moved to this state):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Web.Mvc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Xml&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;SessionState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SessionStateBehavior&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadOnly&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApiController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BaseController&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For an &lt;code&gt;ApiController&lt;/code&gt; that does (or should not) work on the session this should be the default behavior.&lt;/p&gt;

&lt;p&gt;As far as the cache goes the standard ASP.NET cache behaves rather poorly on the app service. What we can do is to introduce a &lt;code&gt;ConcurrentDictionary&lt;/code&gt; to handle this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ConcurrentDictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This, of course, only works because we are restricted to a single instance. If the website would run in a multi-instance mode we'd need a different solution such as as a Redis cache (alternatively, we could then use the ASP.NET cache as it is automatically synced within an app service).&lt;/p&gt;

&lt;p&gt;We introduce two convenience methods to control the cache.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;GetOrAddCache&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Func&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; 
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetOrAdd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ResetCache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryRemove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As an example the &lt;code&gt;FindAllTags&lt;/code&gt; method to retrieve all tags now looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Tag&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;FindAllTags&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;GetOrAddCache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FindAllTags&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Tags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Tag&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Likewise, when we mutate the tags we also need to reset the cache. Here the &lt;code&gt;Delete(Tag)&lt;/code&gt; method had to be adjusted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Tag&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Tags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DeleteEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PartitionKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RowKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;ResetCache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FindAllTags&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With everything in place we can now compare the behavior of the website with these changes (running in the cloud) to the previous solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparison
&lt;/h2&gt;

&lt;p&gt;We started with the news overview page taking between 16ms and 25ms. This was on the dedicated server, with the database being integrated (i.e., running on the same machine) as a MySQL database.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs3lyxql4ydcqpkop59wq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs3lyxql4ydcqpkop59wq.png" alt="The website as running on a dedicated server" width="800" height="594"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, we are running in Azure using an Azure App Service. We had to use a Windows ASP.NET MVC 4 compatible App Service plan, which is a bit pricey (total cost would be a bit higher than we previously had) - but due to my monthly Azure allowance still much cheaper than beforehand.&lt;/p&gt;

&lt;p&gt;With everything in place we reach times between 4ms and 50ms. The average is between 8ms and 10ms. That the variance is higher is not actually a problem, as long as the worst result is within the 100ms time frame.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvbjfew0aekuusotev1as.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvbjfew0aekuusotev1as.png" alt="The website as running on a cheap app service in the cloud" width="800" height="594"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As the average time is now much better than beforehand I'm (on average) happy. Still, I potentially could have achieved the same time on the dedicated machine; I only should have looked. But since I thought the performance is good enough I did not spend more time on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;1️⃣ Migrate away from the custom analytics solution to Azure App Insights (or some other service - ideally one with a possible data import)&lt;/p&gt;

&lt;p&gt;2️⃣ Put everything into a SSG such as Astro, i.e., generate the page fully at build (hopefully incrementally to avoid building 1000s of pages every time something small changes)&lt;/p&gt;

&lt;p&gt;3️⃣ Use micro frontends to bring in little islands of interactivity that can be updated / deployed independently of the SSG part&lt;/p&gt;

&lt;p&gt;The latter would only be interesting for the parts that definitely require JavaScript or data at runtime, such as the current list of articles on other websites ("stream" on the homepage) or things such as little games that are available on the page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;It runs - faster, more modern, and far more cost efficient (for the given subdomains no additional costs occur). The crucial part was to identify a way of providing the content in a mode that fits its purpose best.&lt;/p&gt;

&lt;p&gt;With an average memory allocation never exceeding 70% and a peak CPU utilization of 30% I think the chosen plan works out nicely. While the plan would usually cost around 30 € monthly (thus certainly not being cheaper than my dedicated hosting beforehand) the monthly Azure allowance reduces that to 0 €.&lt;/p&gt;

&lt;p&gt;So overall the payment for the infrastructure was reduced significantly. Previously I had to pay about 30 € per month for the hosting - now it's just $5. In total I am now at 15% of the original cost. Surely, if the monthly Azure allowance would not be in there - that ratio would not be the same - but let's not forget that the page does not need to run on an Azure App Service plan.&lt;/p&gt;

&lt;p&gt;In the long run I will migrate it to a fully static page - thus not requiring much infrastructure and being far more efficient. But this is the content for another story...&lt;/p&gt;

&lt;p&gt;🙏 Thanks for following my migration and happy coding everyone!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>dotnet</category>
      <category>azure</category>
    </item>
  </channel>
</rss>
