<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Daishi Kato&#39;s Read the Code</title>
    <description>A newsletter by Daishi Kato exploring coding and open source.</description>
    
    <link>https://newsletter.daishikato.com/</link>
    <atom:link href="https://rss.beehiiv.com/feeds/Zf28He81Go.xml" rel="self"/>
    
    <lastBuildDate>Sat, 16 May 2026 03:30:02 +0000</lastBuildDate>
    <pubDate>Wed, 13 May 2026 15:00:00 +0000</pubDate>
    <atom:published>2026-05-13T15:00:00Z</atom:published>
    <atom:updated>2026-05-16T03:30:02Z</atom:updated>
    
      <category>Programming</category>
    <copyright>Copyright 2026, Daishi Kato&#39;s Read the Code</copyright>
    
    <image>
      <url>https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/publication/logo/6a161b22-6750-4c2d-8b7c-60fdfa288586/speaking2-avatar1.png</url>
      <title>Daishi Kato&#39;s Read the Code</title>
      <link>https://newsletter.daishikato.com/</link>
    </image>
    
    <docs>https://www.rssboard.org/rss-specification</docs>
    <generator>beehiiv</generator>
    <language>en-us</language>
    <webMaster>support@beehiiv.com (Beehiiv Support)</webMaster>

      <item>
  <title>How Waku Implements File-System Routing</title>
  <description>It’s Only 172 LOC</description>
  <link>https://newsletter.daishikato.com/p/how-waku-implements-file-system-routing</link>
  <guid isPermaLink="true">https://newsletter.daishikato.com/p/how-waku-implements-file-system-routing</guid>
  <pubDate>Wed, 13 May 2026 15:00:00 +0000</pubDate>
  <atom:published>2026-05-13T15:00:00Z</atom:published>
    <dc:creator>Daishi Kato</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><p class="paragraph" style="text-align:left;">Hi,</p><p class="paragraph" style="text-align:left;">We released Waku v1.0.0-beta.0 recently.</p><p class="paragraph" style="text-align:left;">Check out: <a class="link" href="https://waku.gg/blog/waku-v1-beta?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=how-waku-implements-file-system-routing" target="_blank" rel="noopener noreferrer nofollow">https://waku.gg/blog/waku-v1-beta</a></p><p class="paragraph" style="text-align:left;">Waku is a minimal React framework, and by that I mean it’s minimal from both a framework user perspective and a framework developer perspective.</p><p class="paragraph" style="text-align:left;">Config-Based Router</p><p class="paragraph" style="text-align:left;">For the router, we first developed a config-based router, which is a lower-level API. We then developed a wrapper layer to implement a file-system-based router.</p><p class="paragraph" style="text-align:left;">It’s basically a one-to-one mapping. For example, with the config router, we do:</p><div class="codeblock"><pre><code>createPage(&#123;
  path: &#39;/hello&#39;,
  component: () =&gt; &lt;h1&gt;Hello&lt;/h1&gt;,
  render: &#39;dynamic&#39;,t
&#125;)</code></pre></div><p class="paragraph" style="text-align:left;">File-System Router</p><p class="paragraph" style="text-align:left;">For the same route, what we do with the file-system router is:</p><div class="codeblock"><pre><code>// ./src/pages/hello.tsx
export default function() &#123;
  return &lt;h1&gt;Hello&lt;/h1&gt;
&#125;

export const getConfig = async () =&gt; &#123;
  return &#123;
    render: &#39;dynamic&#39;,
  &#125;;
&#125;;</code></pre></div><p class="paragraph" style="text-align:left;">The <code>path</code> and <code>component</code> parts are automatically inferred, and the rest is provided by the <code>getConfig</code> function.</p><p class="paragraph" style="text-align:left;">Capability-wise, the config router and the file-system router are equivalent. It’s just a stylistic difference.</p><p class="paragraph" style="text-align:left;">If you are interested, check out the <a class="link" href="https://github.com/wakujs/waku/blob/27e83f0b1a1554f12b049b07e9101d1db8483f5e/packages/waku/src/router/fs-router.ts?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=how-waku-implements-file-system-routing" target="_blank" rel="noopener noreferrer nofollow">source code</a>, which is only 172 loc.</p><p class="paragraph" style="text-align:left;">Happy coding.</p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=d610b265-2565-4c67-a8c9-2d081fbc5252&utm_medium=post_rss&utm_source=daishi_kato_s_read_the_code">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>Jotai v2.20.0 and the Store Building Blocks</title>
  <description>A small performance fix with a long history</description>
  <link>https://newsletter.daishikato.com/p/jotai-v2-20-0-and-the-store-building-blocks</link>
  <guid isPermaLink="true">https://newsletter.daishikato.com/p/jotai-v2-20-0-and-the-store-building-blocks</guid>
  <pubDate>Sat, 09 May 2026 15:00:00 +0000</pubDate>
  <atom:published>2026-05-09T15:00:00Z</atom:published>
    <dc:creator>Daishi Kato</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><p class="paragraph" style="text-align:left;">Hi,</p><p class="paragraph" style="text-align:left;">It was more than one year ago when we released Jotai v2.12.0.</p><p class="paragraph" style="text-align:left;"><a class="link" href="https://github.com/pmndrs/jotai/releases/tag/v2.12.0?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=jotai-v2-20-0-and-the-store-building-blocks" target="_blank" rel="noopener noreferrer nofollow">https://github.com/pmndrs/jotai/releases/tag/v2.12.0</a></p><p class="paragraph" style="text-align:left;">It introduced a new idea to expose some internals so that ecosystem libraries can extend Jotai&#39;s core capabilities. It was collaborative work with David Maskasky, who is the maintainer of jotai-effect, jotai-scope, and so on.</p><h1 class="heading" style="text-align:left;" id="why-building-blocks">Why Building Blocks</h1><p class="paragraph" style="text-align:left;">I didn&#39;t like extending the store after creation, because that would cause some mismatches, like having two different capabilities over time. What I chose was to accept customization at the time of building a new store. I call this customization method the building blocks of a store.</p><p class="paragraph" style="text-align:left;">The initial implementation was somewhat limited. It didn&#39;t provide full customization, and the API was a little bit hard to deal with.</p><p class="paragraph" style="text-align:left;">Over time, we&#39;ve improved it. Around v2.15.0, we mostly finished it, and the API became both flexible and safe, or hard to misuse.</p><h1 class="heading" style="text-align:left;" id="performance-regression">Performance Regression</h1><p class="paragraph" style="text-align:left;">A long time later, at least for me, someone reported that there seemed to be a performance regression. The major reason was the use of WeakMap, which was meant to improve the flexibility of building blocks.</p><p class="paragraph" style="text-align:left;">See more: <a class="link" href="https://github.com/pmndrs/jotai/pull/3280?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=jotai-v2-20-0-and-the-store-building-blocks" target="_blank" rel="noopener noreferrer nofollow">https://github.com/pmndrs/jotai/pull/3280</a></p><p class="paragraph" style="text-align:left;">We iterated on ideas to solve it, and I decided to go with one idea, which is not super clean, but fits with my mental model. Basically, instead of using WeakMap, it now passes everything as parameters.</p><h1 class="heading" style="text-align:left;" id="toward-jotai-v-3">Toward Jotai v3</h1><p class="paragraph" style="text-align:left;">Many users don&#39;t need to understand the subtlety. But I just wanted to share that there was some history behind it.</p><p class="paragraph" style="text-align:left;">Jotai v2.20.0 was released a couple of days ago.</p><p class="paragraph" style="text-align:left;"><a class="link" href="https://github.com/pmndrs/jotai/releases/tag/v2.20.0?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=jotai-v2-20-0-and-the-store-building-blocks" target="_blank" rel="noopener noreferrer nofollow">https://github.com/pmndrs/jotai/releases/tag/v2.20.0</a></p><p class="paragraph" style="text-align:left;">Now, I&#39;m ready to think about Jotai v3.</p><p class="paragraph" style="text-align:left;">Happy coding.</p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=a46a31c0-a036-47b8-9c6f-70f659dd0780&utm_medium=post_rss&utm_source=daishi_kato_s_read_the_code">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>My Thoughts on RSC: Is It Just Serialization?</title>
  <description>How Waku Has Evolved</description>
  <link>https://newsletter.daishikato.com/p/my-thoughts-on-rsc-is-it-just-serialization</link>
  <guid isPermaLink="true">https://newsletter.daishikato.com/p/my-thoughts-on-rsc-is-it-just-serialization</guid>
  <pubDate>Mon, 27 Apr 2026 15:00:00 +0000</pubDate>
  <atom:published>2026-04-27T15:00:00Z</atom:published>
    <dc:creator>Daishi Kato</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><p class="paragraph" style="text-align:left;">Hi,</p><p class="paragraph" style="text-align:left;">Is RSC a data protocol or an architectural design? I had a similar question when I started developing Waku, or even before that.</p><h1 class="heading" style="text-align:left;" id="early-motivation">Early Motivation</h1><p class="paragraph" style="text-align:left;">As a library author, my interest was the serialization algorithm. Actually, I made a library called <a class="link" href="https://github.com/dai-shi/react-worker-components?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=my-thoughts-on-rsc-is-it-just-serialization" target="_blank" rel="noopener noreferrer nofollow">react-worker-components</a>, which includes a homegrown serialization algorithm supporting references. So, my first goal with Waku was to wire up RSC&#39;s serialization capability into something usable. It was like a DEV-only playground for RSC.</p><h1 class="heading" style="text-align:left;" id="adding-production-build-support">Adding Production Build Support</h1><p class="paragraph" style="text-align:left;">Later, it introduced bundling thanks to Vite and many custom plugins, which can generate a production build.</p><p class="paragraph" style="text-align:left;">Around that time, while discussing with someone at the React team, I noticed RSC was a broader concept. For example, an RSC framework shouldn&#39;t encourage some bad practices like client-server waterfalls, which is one of the biggest problems RSC was trying to solve. So, I changed Waku&#39;s API so that it eased, or more or less forced, a single round-trip request and response API.</p><h1 class="heading" style="text-align:left;" id="library-interoperability">Library Interoperability</h1><p class="paragraph" style="text-align:left;">Another example is library interoperability. There&#39;s a library called <a class="link" href="https://react-tweet.vercel.app/?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=my-thoughts-on-rsc-is-it-just-serialization" target="_blank" rel="noopener noreferrer nofollow">react-tweet</a>. It&#39;s a pure RSC library and is not tied to Next.js. Many fixes have been done in Waku to support it and similar libraries.</p><p class="paragraph" style="text-align:left;">Another library to tackle was the <a class="link" href="https://ai-sdk.dev/docs/introduction?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=my-thoughts-on-rsc-is-it-just-serialization" target="_blank" rel="noopener noreferrer nofollow">AI SDK</a>. It uses RSC extensively, and it was challenging, but we made it work.</p><h1 class="heading" style="text-align:left;" id="rsc-as-architecture">RSC as Architecture</h1><p class="paragraph" style="text-align:left;">Nowadays, React docs include <a class="link" href="https://react.dev/reference/rsc/server-components?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=my-thoughts-on-rsc-is-it-just-serialization" target="_blank" rel="noopener noreferrer nofollow">RSC stuff</a>, and it&#39;s clearer than before that RSC is not just serialization logic, but the entire architecture with best practices. That said, I think there is still room for more documentation.</p><p class="paragraph" style="text-align:left;">Waku should be a full RSC framework. If you find some bugs, feel free to report them.</p><p class="paragraph" style="text-align:left;">Happy coding.</p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=758332f1-3dec-486e-92e7-d1f33df115eb&utm_medium=post_rss&utm_source=daishi_kato_s_read_the_code">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>Behind the APIs: How Zustand, Jotai, and Valtio Were Born</title>
  <description>My Talk at React Paris 2026</description>
  <link>https://newsletter.daishikato.com/p/behind-the-apis-how-zustand-jotai-and-valtio-were-born</link>
  <guid isPermaLink="true">https://newsletter.daishikato.com/p/behind-the-apis-how-zustand-jotai-and-valtio-were-born</guid>
  <pubDate>Fri, 10 Apr 2026 15:00:00 +0000</pubDate>
  <atom:published>2026-04-10T15:00:00Z</atom:published>
    <dc:creator>Daishi Kato</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><p class="paragraph" style="text-align:left;">Hi,</p><p class="paragraph" style="text-align:left;">Last month, I visited Paris, France, to attend the conference React Paris 2026. It&#39;s a long journey from Japan, but visiting a place far away gives me some excitement.</p><h1 class="heading" style="text-align:left;" id="my-talk">My Talk</h1><p class="paragraph" style="text-align:left;">I gave a talk at the conference on the first day about my history of developing state management libraries. They were not created randomly. I had clear goals, and it happened to become multiple libraries.</p><h1 class="heading" style="text-align:left;" id="watch-the-talk">Watch the Talk</h1><p class="paragraph" style="text-align:left;">You can watch my talk on YouTube:</p><iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="true" class="youtube_embed" frameborder="0" height="100%" src="https://youtube.com/embed/gQ0PsCWvn3I" width="100%"></iframe><p class="paragraph" style="text-align:left;">Happy coding.</p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=3b29b836-6ebf-4768-a89b-e92c67cd5cc7&utm_medium=post_rss&utm_source=daishi_kato_s_read_the_code">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>My Thoughts on AI-Generated PRs for My OSS Projects</title>
  <description>What Contributors Can Do to Help</description>
  <link>https://newsletter.daishikato.com/p/my-thoughts-on-ai-generated-prs-for-my-oss-projects</link>
  <guid isPermaLink="true">https://newsletter.daishikato.com/p/my-thoughts-on-ai-generated-prs-for-my-oss-projects</guid>
  <pubDate>Fri, 06 Mar 2026 15:00:00 +0000</pubDate>
  <atom:published>2026-03-06T15:00:00Z</atom:published>
    <dc:creator>Daishi Kato</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><p class="paragraph" style="text-align:left;">Hi,</p><p class="paragraph" style="text-align:left;">AI-assisted coding is great, without a doubt. But when it comes to OSS contributions, the story is a bit more complicated.</p><h1 class="heading" style="text-align:left;" id="the-problem">The Problem</h1><p class="paragraph" style="text-align:left;">For my OSS projects, when I receive a PR, I need to look into it. At that point, I do not know how much AI assistance was used. Let us take an extreme case. If a PR is 100% AI-generated, I need to review it instead of the contributor, and I need to ask the contributor to fix it if necessary. That feels like a real waste.</p><p class="paragraph" style="text-align:left;">I should just ask the AI directly. Or, what is even better is to ask the AI from the start. Then I know the full context, what AI I am using, what I asked, and how I should control it. Having a human contributor is pure overhead.</p><p class="paragraph" style="text-align:left;">Of course, that is not the case if the original PR is perfect. But that is unlikely, because not everything is in the code base and the docs. Although small, there is something in my brain that is not exposed. It is probably impossible, because I do not know what it is. It is like my preference, but I do not know it until I get asked.</p><h1 class="heading" style="text-align:left;" id="what-contributors-can-do">What Contributors Can Do</h1><p class="paragraph" style="text-align:left;">That was an extreme case, but even if the contributor did some review of the AI-generated code, things do not change a lot. Unless humans do more work, it does not make sense. That is only possible for those who can do the work without AI.</p><p class="paragraph" style="text-align:left;">So, what do I think would work? I think after reporting issues, sending a PR with a failing test would help, but solutions should not be included. The failing test can be assisted by AI, as long as the human reviews it, and the test is human-readable, representing the spec.</p><h1 class="heading" style="text-align:left;" id="final-thoughts">Final Thoughts</h1><p class="paragraph" style="text-align:left;">This idea might be controversial, but it is what I feel now. It can change when things change, which can happen pretty soon in this AI era.</p><p class="paragraph" style="text-align:left;">Happy coding.</p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=ad7b73eb-9fab-41b5-8199-48fb973d567a&utm_medium=post_rss&utm_source=daishi_kato_s_read_the_code">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>Community Drives the Ecosystem Forward</title>
  <description>Recent Community Contributions Across My Projects</description>
  <link>https://newsletter.daishikato.com/p/community-drives-the-ecosystem-forward</link>
  <guid isPermaLink="true">https://newsletter.daishikato.com/p/community-drives-the-ecosystem-forward</guid>
  <pubDate>Sun, 08 Feb 2026 15:00:05 +0000</pubDate>
  <atom:published>2026-02-08T15:00:05Z</atom:published>
    <dc:creator>Daishi Kato</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><p class="paragraph" style="text-align:left;">Hi,</p><p class="paragraph" style="text-align:left;">Today, I&#39;d like to talk about community contributions. In the past couple of weeks, several PRs from community contributors landed across my projects. I think this is worth sharing.</p><h3 class="heading" style="text-align:left;" id="zustand-v-5011">Zustand v5.0.11</h3><p class="paragraph" style="text-align:left;">I released Zustand v5.0.11 on February 1st. It is a patch release, but all three fixes came from community contributors.</p><p class="paragraph" style="text-align:left;">The devtools middleware got better typing. The persist middleware was fixed to not rely on the global <code>localStorage</code> directly. This matters in environments where <code>localStorage</code> is not available. And the immer middleware typing was improved for the slices pattern.</p><p class="paragraph" style="text-align:left;">None of these are flashy changes. They are the kind of improvements that quietly make a library more reliable.</p><p class="paragraph" style="text-align:left;">I should also mention v5.0.10, which included a fix for a race condition during concurrent rehydrate calls in the persist middleware. That PR required patience from the contributor, who waited through the review process. The result is solid.</p><h3 class="heading" style="text-align:left;" id="excalidraw-animate">Excalidraw Animate</h3><p class="paragraph" style="text-align:left;">Someone submitted Playwright E2E tests for excalidraw-animate. I requested some changes during review. After the fixes, I merged it. It is good to see testing infrastructure being added to this project by someone other than me.</p><h3 class="heading" style="text-align:left;" id="waku">Waku</h3><p class="paragraph" style="text-align:left;">In Waku, a new contributor made their first contribution by fixing middleware auto-discovery to exclude test files. A Spanish-language learning resource was contributed and merged. And a Netlify dynamic routes bug was fixed by a community member.</p><h3 class="heading" style="text-align:left;" id="why-this-matters">Why This Matters</h3><p class="paragraph" style="text-align:left;">I maintain these projects, but I cannot catch everything. Middleware edge cases, test infrastructure, documentation in other languages. These contributions come from people using the libraries in ways I do not. That is what makes open source better than what any single developer can do.</p><p class="paragraph" style="text-align:left;">If you want to contribute to any of these projects, there are always open discussions and issues to work on. Do not hesitate.</p><p class="paragraph" style="text-align:left;">Happy coding.</p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=5022151d-a30f-40ad-8b66-2abe114491bc&utm_medium=post_rss&utm_source=daishi_kato_s_read_the_code">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>We need OSS docs that LLMs can consume</title>
  <description>Time to think about Jotai Skills</description>
  <link>https://newsletter.daishikato.com/p/we-need-oss-docs-that-llms-can-consume</link>
  <guid isPermaLink="true">https://newsletter.daishikato.com/p/we-need-oss-docs-that-llms-can-consume</guid>
  <pubDate>Thu, 22 Jan 2026 15:00:54 +0000</pubDate>
  <atom:published>2026-01-22T15:00:54Z</atom:published>
    <dc:creator>Daishi Kato</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><p class="paragraph" style="text-align:left;">Hi,</p><p class="paragraph" style="text-align:left;">Last year, one of my activities was thinking about how to monetize my OSS products, and it is still a topic this year too. The software itself is free, so what could we sell? I guess documents for OSS can be info products. But people do not often buy OSS documents, right? My hypothesis is that when AI-assisted coding becomes more common, AI can buy info products to accomplish tasks. A human might confirm it, or they might not even notice.</p><h1 class="heading" style="text-align:left;" id="jotai-techniques">Jotai Techniques</h1><p class="paragraph" style="text-align:left;">For such a future, I was planning to create &quot;Jotai Techniques&quot;, which would be a collection of examples to showcase good uses of Jotai. It is kind of an experiment in how LLMs can utilize it. I also explored the use of MCP servers to provide the info product with authentication. Check out <a class="link" href="https://github.com/jotaijs/jotai-mcp-server?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=we-need-oss-docs-that-llms-can-consume" target="_blank" rel="noopener noreferrer nofollow">https://github.com/jotaijs/jotai-mcp-server</a>.</p><h1 class="heading" style="text-align:left;" id="why-it-did-not-take-off">Why it did not take off</h1><p class="paragraph" style="text-align:left;">However, the idea of &quot;Jotai Techniques&quot; never took off. There are several reasons.</p><p class="paragraph" style="text-align:left;">For one, I am not good at writing docs, and I enjoy coding if I have time. Another is that I was not sure how to make a convincing case for this idea. I could try a small task with AI-assisted coding with and without &quot;Jotai Techniques&quot;, and compare the results. But AI is evolving too fast, and the evaluation would get stale too soon. Lastly, it is still not the age where AI buys something behind the scenes. It will take more time.</p><h1 class="heading" style="text-align:left;" id="jotai-skills">Jotai Skills</h1><p class="paragraph" style="text-align:left;">So, I gave up this idea. Now that agent skills are getting popular, I think we should work on &quot;Jotai Skills&quot;. That is very close to my original idea of &quot;Jotai Techniques&quot; last year, only partially though.</p><p class="paragraph" style="text-align:left;">Unfortunately, I am not motivated to lead this project alone, so I decided to call for collaborators:<br><a class="link" href="https://github.com/pmndrs/jotai/discussions/3221?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=we-need-oss-docs-that-llms-can-consume" target="_blank" rel="noopener noreferrer nofollow">https://github.com/pmndrs/jotai/discussions/3221</a></p><p class="paragraph" style="text-align:left;">I look forward to it.</p><p class="paragraph" style="text-align:left;">Happy coding.</p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=25f5eac6-a5cc-493a-8ee4-bbfb0cef4b12&utm_medium=post_rss&utm_source=daishi_kato_s_read_the_code">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>Waku v1 Alpha Is Finally Released</title>
  <description>Nearly Three Years in the Making</description>
  <link>https://newsletter.daishikato.com/p/waku-v1-alpha-is-finally-released</link>
  <guid isPermaLink="true">https://newsletter.daishikato.com/p/waku-v1-alpha-is-finally-released</guid>
  <pubDate>Wed, 24 Dec 2025 15:00:17 +0000</pubDate>
  <atom:published>2025-12-24T15:00:17Z</atom:published>
    <dc:creator>Daishi Kato</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><p class="paragraph" style="text-align:left;">Hi,</p><p class="paragraph" style="text-align:left;">We just released Waku v1.0.0-alpha.0. Our public API has been stable for some time, and it is ready for wider adoption. Check out our blog post:</p><div class="embed"><a class="embed__url" href="https://waku.gg/blog/waku-v1-alpha?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=waku-v1-alpha-is-finally-released" target="_blank"><div class="embed__content"><p class="embed__title"> Waku 1.0 (alpha) — Waku </p><p class="embed__description"> Waku&#39;s public APIs are now marked as stable. </p><p class="embed__link"> waku.gg/blog/waku-v1-alpha </p></div><img class="embed__image embed__image--right" src="https://cdn.candycode.com/waku/opengraph.jpg"/></a></div><p class="paragraph" style="text-align:left;">It has been almost three years since I started this project. It was originally called Wakuwork:</p><blockquote align="center" class="twitter-tweet"><a href="https://twitter.com/dai_shi/status/1631668890861441024?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=waku-v1-alpha-is-finally-released"><p> Twitter tweet </p></a></blockquote><p class="paragraph" style="text-align:left;">It started as my personal experiment, but soon after that, some collaborators joined, and we decided to aim for a production-ready framework. Waku v0.18 was released two years ago:</p><div class="embed"><a class="embed__url" href="https://waku.gg/blog/introducing-waku?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=waku-v1-alpha-is-finally-released" target="_blank"><div class="embed__content"><p class="embed__title"> Introducing Waku — Waku </p><p class="embed__description"> Learn about the minimal React framework and how it enables RSC features. </p><p class="embed__link"> waku.gg/blog/introducing-waku </p></div><img class="embed__image embed__image--right" src="https://cdn.candycode.com/waku/opengraph.jpg"/></a></div><p class="paragraph" style="text-align:left;">We have received a lot of feedback since then, and we have improved our APIs and implementations. I’m proud of it, and I appreciate all contributors.</p><p class="paragraph" style="text-align:left;">Happy coding.</p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=7e62da45-f579-4ad1-a18b-8273a206a12d&utm_medium=post_rss&utm_source=daishi_kato_s_read_the_code">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>My Podcast Interview: An Open-Style Q&amp;A</title>
  <description>State Management at Scale</description>
  <link>https://newsletter.daishikato.com/p/my-podcast-interview-an-open-style-q-a</link>
  <guid isPermaLink="true">https://newsletter.daishikato.com/p/my-podcast-interview-an-open-style-q-a</guid>
  <pubDate>Tue, 16 Dec 2025 15:00:34 +0000</pubDate>
  <atom:published>2025-12-16T15:00:34Z</atom:published>
    <dc:creator>Daishi Kato</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><p class="paragraph" style="text-align:left;">Hi,</p><p class="paragraph" style="text-align:left;">I was interviewed for a podcast episode, and it is now available on YouTube. Check it out <a class="link" href="https://www.youtube.com/watch?v=ns8ith5cu-U&utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=my-podcast-interview-an-open-style-q-a" target="_blank" rel="noopener noreferrer nofollow">here</a>.</p><p class="paragraph" style="text-align:left;">This was one of my unusual talks, because I did not prepare much for the interview. Usually, I prepare scripts for my talks, because I’m not great at speaking spontaneously, not only in English, but also in my native tongue. So, this one was special.</p><p class="paragraph" style="text-align:left;">In the past, I did some podcast episodes, and I wrote scripts in advance. Check out <a class="link" href="https://blog.axlight.com/posts/my-react-talks-to-date-in-various-formats/?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=my-podcast-interview-an-open-style-q-a" target="_blank" rel="noopener noreferrer nofollow">this blog post</a> for my past talks, and <a class="link" href="https://newsletter.daishikato.com/p/developing-waku-and-exploring-client-state-with-react-server-components?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=my-podcast-interview-an-open-style-q-a" target="_blank" rel="noopener noreferrer nofollow">my previous newsletter</a> for my latest conference talk, in case you missed it.</p><p class="paragraph" style="text-align:left;">Happy coding.</p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=4e0a0633-f7a6-4330-a6b1-19fec17a11b2&utm_medium=post_rss&utm_source=daishi_kato_s_read_the_code">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>Developing Waku and Exploring Client State with React Server Components</title>
  <description>My Talk at React Alicante 2025</description>
  <link>https://newsletter.daishikato.com/p/developing-waku-and-exploring-client-state-with-react-server-components</link>
  <guid isPermaLink="true">https://newsletter.daishikato.com/p/developing-waku-and-exploring-client-state-with-react-server-components</guid>
  <pubDate>Sat, 13 Dec 2025 15:00:07 +0000</pubDate>
  <atom:published>2025-12-13T15:00:07Z</atom:published>
    <dc:creator>Daishi Kato</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><p class="paragraph" style="text-align:left;">Hi,</p><p class="paragraph" style="text-align:left;">On October 3, 2025, I gave a talk at the React Alicante 2025 conference. To my memory, this was probably the longest conference talk I’ve ever done.</p><h1 class="heading" style="text-align:left;" id="talk-overview">Talk Overview</h1><p class="paragraph" style="text-align:left;">The talk covers a basic introduction to Waku, and why I created it. I also talk about what motivated me to start developing a new React framework. I showed an experimental library called <code>waku-jotai</code>, which was kind of my original motivation.</p><h1 class="heading" style="text-align:left;" id="recording">Recording</h1><p class="paragraph" style="text-align:left;">Check out the recording video <a class="link" href="https://www.youtube.com/watch?v=t1QlBrngjdI&utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=developing-waku-and-exploring-client-state-with-react-server-components" target="_blank" rel="noopener noreferrer nofollow">here</a>.</p><h1 class="heading" style="text-align:left;" id="try-waku">Try Waku</h1><p class="paragraph" style="text-align:left;">If you have not tried Waku yet, give it a spin. Hope you like it.</p><p class="paragraph" style="text-align:left;">Happy coding.</p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=2c51f683-733f-43a6-b281-68d1576c6859&utm_medium=post_rss&utm_source=daishi_kato_s_read_the_code">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>I Just Launched the Zustand Banner Sponsorship Program</title>
  <description>Another Challenge for Monetizing OSS</description>
  <link>https://newsletter.daishikato.com/p/i-just-launched-the-zustand-banner-sponsorship-program</link>
  <guid isPermaLink="true">https://newsletter.daishikato.com/p/i-just-launched-the-zustand-banner-sponsorship-program</guid>
  <pubDate>Wed, 26 Nov 2025 15:00:26 +0000</pubDate>
  <atom:published>2025-11-26T15:00:26Z</atom:published>
    <dc:creator>Daishi Kato</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><p class="paragraph" style="text-align:left;">Hi,</p><p class="paragraph" style="text-align:left;">About four years ago, I started seriously considering monetizing OSS. Generally speaking, I develop OSS for my personal fun. It is not a job someone requested me to do, but something that I enjoy developing without other forces. I do not need to get paid for fun.</p><p class="paragraph" style="text-align:left;">However, there are several issues for me. One is that I need to pay bills and prepare for the future. So, I need to earn money. Contract work helps, but usually it is not very related to my OSS projects. (BTW, I am open to an opportunity that is related to them.) So, it would be great if I can earn money directly from my OSS projects. Another issue is that while I enjoy very much starting a new project, maintaining it is a different story. I am proud of projects going well and I do not mean that I dislike maintaining them. That said, maintaining projects involves many non-coding tasks (while I love coding), and there are many chores and sometimes stressful things. So, it would be great to have some incentives, in this case, money.</p><h1 class="heading" style="text-align:left;" id="past-attempts">Past Attempts</h1><p class="paragraph" style="text-align:left;">A long time ago, I created some <a class="link" href="https://egghead.io/q/resources-by-daishi-kato?af=egwzez&utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=i-just-launched-the-zustand-banner-sponsorship-program" target="_blank" rel="noopener noreferrer nofollow">courses</a>, <a class="link" href="https://www.educative.io/profile/view/6060404088242176?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=i-just-launched-the-zustand-banner-sponsorship-program" target="_blank" rel="noopener noreferrer nofollow">tutorials</a> and a <a class="link" href="https://www.amazon.co.jp/Micro-State-Management-React-Hooks/dp/1801812373?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=i-just-launched-the-zustand-banner-sponsorship-program" target="_blank" rel="noopener noreferrer nofollow">book</a>. It was a good experience, but it took much time. I realized that I should spend more time on coding than creating courses. In 2022, I tried <a class="link" href="https://x.com/dai_shi/status/1489205927542591488?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=i-just-launched-the-zustand-banner-sponsorship-program" target="_blank" rel="noopener noreferrer nofollow">something</a> different. I created a simple info product (like a tutorial video) that is not like a full course, but something much easier to create. The point of it was that the fee was not only for the info product itself, but also for supporting the project. However, it was more or less a one-time small donation and it does not last long unless we keep promoting it, which is too much work for me.</p><p class="paragraph" style="text-align:left;">I think the general problem is that we should not expect individual developers to donate from their own pocket money. I think we should get sponsorship from companies who inherently get benefits from the OSS projects. That is kind of obvious, and someone advised me in the past as well. So, I decided to take on another challenge.</p><h1 class="heading" style="text-align:left;" id="using-git-hub-sponsors">Using GitHub Sponsors</h1><p class="paragraph" style="text-align:left;">This time, I use GitHub Sponsors. I have already configured my GitHub Sponsors dashboard, but I did not pay much attention to sponsor tiers. Especially, I did not provide any specific rewards. This is because my assumption is that my product is my outcome. However, in recent years, I have learned that rewards are actually important for sponsorship.</p><p class="paragraph" style="text-align:left;">The sponsorship program is called &quot;Zustand Banner Sponsorship&quot; and the idea is simple. We put sponsor logos in our README.md. I think it is pretty normal for sponsorship rewards.</p><h1 class="heading" style="text-align:left;" id="how-the-banner-works">How the Banner Works</h1><p class="paragraph" style="text-align:left;">As I do not want to change README.md every time sponsors change, I made a small website to show the list of sponsors and provide a banner image showing all sponsor logos, which will be embedded in README.md. I made this website with <a class="link" href="https://waku.gg?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=i-just-launched-the-zustand-banner-sponsorship-program" target="_blank" rel="noopener noreferrer nofollow">Waku</a> and hosted it on GitHub Pages.</p><p class="paragraph" style="text-align:left;">If you are interested, check out the banner image at the <a class="link" href="https://github.com/pmndrs/zustand?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=i-just-launched-the-zustand-banner-sponsorship-program" target="_blank" rel="noopener noreferrer nofollow">Zustand</a> repository and click the banner.</p><p class="paragraph" style="text-align:left;">If you are interested in sponsoring, click the &quot;How to become a sponsor&quot; button.</p><p class="paragraph" style="text-align:left;">Happy coding.</p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=da72f048-9acb-408a-a03d-54380232a08e&utm_medium=post_rss&utm_source=daishi_kato_s_read_the_code">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>What’s New in Waku v0.27.1</title>
  <description>A major improvement in a patch release</description>
  <link>https://newsletter.daishikato.com/p/what-s-new-in-waku-v0-27-1</link>
  <guid isPermaLink="true">https://newsletter.daishikato.com/p/what-s-new-in-waku-v0-27-1</guid>
  <pubDate>Wed, 19 Nov 2025 15:00:06 +0000</pubDate>
  <atom:published>2025-11-19T15:00:06Z</atom:published>
    <dc:creator>Daishi Kato</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><p class="paragraph" style="text-align:left;">Hi,</p><p class="paragraph" style="text-align:left;">I just released Waku v0.27.1 this week. It has various fixes and improvements, but I want to emphasize one big improvement. It is a patch release because we do not change any APIs. What is changed is the behavior of static rendering.</p><h1 class="heading" style="text-align:left;" id="static-and-dynamic-parts">Static and Dynamic Parts</h1><p class="paragraph" style="text-align:left;">There had been a limitation that when you mix a static part and a dynamic part in a page, the static part rerenders in some cases. For example, suppose we have a static layout and dynamic pages.</p><div class="codeblock"><pre><code>/static-layout/dynamic-page-1
/static-layout/dynamic-page-2</code></pre></div><p class="paragraph" style="text-align:left;">In terms of HTML, these pages are dynamic anyway, and they always rerender entirely.</p><p class="paragraph" style="text-align:left;">However, with RSC, the components look like this:</p><div class="codeblock"><pre><code>&lt;StaticLayout&gt;
  &lt;DynamicPage1 /&gt;
&lt;/StaticLayout&gt;

&lt;StaticLayout&gt;
  &lt;DynamicPage2 /&gt;
&lt;/StaticLayout&gt;</code></pre></div><p class="paragraph" style="text-align:left;">And we should be able to reuse the static layout if we navigate to dynamic-page-2 from dynamic-page-1.</p><h1 class="heading" style="text-align:left;" id="previous-limitation">Previous Limitation</h1><p class="paragraph" style="text-align:left;">Previously this was already possible when navigating from dynamic-page-1 to dynamic-page-2. StaticLayout did not rerender with soft navigation.</p><p class="paragraph" style="text-align:left;">However, there was a limitation at the initial load. When we first opened dynamic-page-1, it always rendered StaticLayout. And if we did a hard navigation, which is the same as the initial load, it also always rendered.</p><h1 class="heading" style="text-align:left;" id="what-changed-in-v-0271">What Changed in v0.27.1</h1><p class="paragraph" style="text-align:left;">With v0.27.1, we refactored the internals and made sure that StaticLayout only renders once at build time. The technical challenge was finding a way to serialize the static parts of RSC, restore them, and merge them with dynamic parts. The rest was the effort to rework everything with the new architecture, which was not a trivial task.</p><p class="paragraph" style="text-align:left;">I am proud of the outcome, and I expect the new behavior matches what developers intuitively expect. Static means static and only evaluated once.</p><h1 class="heading" style="text-align:left;" id="why-now">Why Now</h1><p class="paragraph" style="text-align:left;">I knew this limitation in Waku existed for a while, but the fix was prioritized after we introduced the Slices API. The new behavior is important for static slices, and now static slices are more powerful.</p><p class="paragraph" style="text-align:left;">Please give the new version of Waku a try and share your thoughts.</p><p class="paragraph" style="text-align:left;"><a class="link" href="https://waku.gg?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=what-s-new-in-waku-v0-27-1" target="_blank" rel="noopener noreferrer nofollow">https://waku.gg</a></p><p class="paragraph" style="text-align:left;">Happy coding.</p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=fab1f876-fe24-4e01-98a2-a0839431e5b1&utm_medium=post_rss&utm_source=daishi_kato_s_read_the_code">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>Waku Gets Slices API Inspired by Gatsby</title>
  <description>It Covers Three Major Use Cases</description>
  <link>https://newsletter.daishikato.com/p/waku-gets-slices-api-inspired-by-gatsby</link>
  <guid isPermaLink="true">https://newsletter.daishikato.com/p/waku-gets-slices-api-inspired-by-gatsby</guid>
  <pubDate>Thu, 14 Aug 2025 15:00:00 +0000</pubDate>
  <atom:published>2025-08-14T15:00:00Z</atom:published>
    <dc:creator>Daishi Kato</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><p class="paragraph" style="text-align:left;">Hi,</p><p class="paragraph" style="text-align:left;">Waku v0.25.0 has been released with a new API. It&#39;s called Slices. The Slices API is inspired by Gatsby&#39;s similar API, at least we took the name. However, I don&#39;t think every detail is the same. We used to have layout and page components, and now, with the new API, slice components.</p><h2 class="heading" style="text-align:left;" id="layouts-and-pages">Layouts and Pages</h2><p class="paragraph" style="text-align:left;">Layouts and pages are based on routing. For the <code>/foo</code> route, we use:</p><div class="codeblock"><pre><code>src/pages/_layout.tsx
src/pages/foo/_layout.tsx
src/pages/foo/index.tsx</code></pre></div><h2 class="heading" style="text-align:left;" id="slices">Slices</h2><p class="paragraph" style="text-align:left;">Slices are isolated from routing. You can define one like:</p><div class="codeblock"><pre><code>src/pages/_slices/bar.tsx</code></pre></div><p class="paragraph" style="text-align:left;">It isn’t served based on routing. We need to explicitly use it in other components. The way we use the slice is as simple as:</p><div class="codeblock"><pre><code>&lt;Slice id=&quot;bar&quot; /&gt;</code></pre></div><h2 class="heading" style="text-align:left;" id="use-cases">Use Cases</h2><p class="paragraph" style="text-align:left;">So, what are the use cases? I think there are at least three.</p><h3 class="heading" style="text-align:left;" id="1-shared-components">1. Shared Components</h3><p class="paragraph" style="text-align:left;">We could use the slice in both <code>/</code> and <code>/foo</code> routes. When we navigate from <code>/</code> to <code>/foo</code>, we can reuse the cached slice component. This makes sense if either <code>/</code> or <code>/foo</code> is dynamic, and the slice component is static. It works only with client navigation (or soft navigation).</p><h3 class="heading" style="text-align:left;" id="2-mixing-dynamic-and-static-parts">2. Mixing Dynamic and Static Parts</h3><p class="paragraph" style="text-align:left;">While it is technically possible with layouts and the <code>(group)</code> syntax, using the Slices API can be more straightforward. If your page is static, you can embed a dynamic slice to mix static and dynamic parts. If your page is dynamic, you can embed a static slice. You can also embed multiple static or dynamic slices regardless of the page type.</p><h3 class="heading" style="text-align:left;" id="3-lazy-slices">3. Lazy Slices</h3><p class="paragraph" style="text-align:left;">This one is a bit different. We call these lazy slices. You use the <code>lazy</code> prop like:</p><div class="codeblock"><pre><code>&lt;Slice id=&quot;bar&quot; lazy fallback=&quot;Loading...&quot; /&gt;</code></pre></div><p class="paragraph" style="text-align:left;">Lazy slices are fetched after the initial rendering and hydration are done. One use case is having a static page with a lazy dynamic slice. If we build the page, it generates HTML statically, which can be placed on a CDN. The dynamic slice is fetched from the server after the client finishes rendering the initial page from the CDN. This is what I call “Waku Islands.”</p><h2 class="heading" style="text-align:left;" id="limitations-and-future-exploration">Limitations and Future Exploration</h2><p class="paragraph" style="text-align:left;">We still have more use cases to explore, but these three are the initial motivations.</p><p class="paragraph" style="text-align:left;">One caveat with slices is that if a slice is not used as a lazy slice and is embedded in a page, the page’s config must include all IDs of slices used in that page. This is a designed limitation. It is a bit tedious, but I hope it is not too much.</p><p class="paragraph" style="text-align:left;">For more information, check out the announcement post at <a class="link" href="https://waku.gg/blog/rethinking-fine-grained-components?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=waku-gets-slices-api-inspired-by-gatsby" target="_blank" rel="noopener noreferrer nofollow">https://waku.gg/blog/rethinking-fine-grained-components</a>.</p><p class="paragraph" style="text-align:left;">Hope you enjoy Waku with the new API.</p><p class="paragraph" style="text-align:left;">Happy coding.</p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=2d177e69-a250-4266-a675-c0d6b407abfd&utm_medium=post_rss&utm_source=daishi_kato_s_read_the_code">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>Waku Gains Vite RSC Support</title>
  <description>It Was a Long Journey to Get Here</description>
  <link>https://newsletter.daishikato.com/p/waku-gains-vite-rsc-support</link>
  <guid isPermaLink="true">https://newsletter.daishikato.com/p/waku-gains-vite-rsc-support</guid>
  <pubDate>Tue, 05 Aug 2025 15:00:00 +0000</pubDate>
  <atom:published>2025-08-05T15:00:00Z</atom:published>
    <dc:creator>Daishi Kato</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><p class="paragraph" style="text-align:left;">Hi,</p><p class="paragraph" style="text-align:left;">I’ve been developing Waku for about 2.5 years now. Waku is a minimal React framework focusing on React Server Components. When I started building it, there was no tech stack I could rely on. I began with a naive Node.js solution using two workers, because the second worker was required to handle the <code>react-server</code> condition.</p><h3 class="heading" style="text-align:left;" id="moving-to-a-single-js-runtime">Moving to a single JS runtime</h3><p class="paragraph" style="text-align:left;">Later, I wanted to avoid a Node.js dependency, and moved to code transformation so that everything could run on a single JS runtime, not necessarily Node.js. That’s when Hono and Vite came into the picture.</p><p class="paragraph" style="text-align:left;">At that point, Waku’s dev server still used two Vite processes for the <code>react-server</code> condition.</p><h3 class="heading" style="text-align:left;" id="vites-rsc-plugin-to-the-rescue">Vite’s RSC plugin to the rescue</h3><p class="paragraph" style="text-align:left;">The long-awaited breakthrough arrived with Vite’s official RSC plugin, including the Environment API. With the Environment API, Waku’s dev server runs on a single Vite instance, and all bundler-specific features are provided by the RSC plugin. This was a great move, because my motivation was never about bundler internals, even though we spent several years building our own Vite-based bundler to support RSC.</p><p class="paragraph" style="text-align:left;">Learn more: <a class="link" href="https://waku.gg/blog/migration-to-vite-plugin-rsc?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=waku-gains-vite-rsc-support" target="_blank" rel="noopener noreferrer nofollow">https://waku.gg/blog/migration-to-vite-plugin-rsc</a></p><h3 class="heading" style="text-align:left;" id="wakus-core-and-whats-next">Waku’s core and what’s next</h3><p class="paragraph" style="text-align:left;">With Vite handling RSC natively, most bundler-specific logic lives outside of Waku itself. Waku’s core is now just a minimal API layer. Beyond this core, Waku provides:</p><ul><li><p class="paragraph" style="text-align:left;">a handy CLI</p></li><li><p class="paragraph" style="text-align:left;">an extensible server</p></li><li><p class="paragraph" style="text-align:left;">an opinionated router based on the minimal API</p></li></ul><p class="paragraph" style="text-align:left;">Now that Vite handles RSC, we can explore more features around React Server Components.</p><p class="paragraph" style="text-align:left;">Happy coding.</p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=4e5fb378-7e64-4762-8a97-858635b7029d&utm_medium=post_rss&utm_source=daishi_kato_s_read_the_code">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>Introducing valtio-reactive: a Reactive Library Built on Valtio</title>
  <description>What Was Missing in Vanilla Valtio</description>
  <link>https://newsletter.daishikato.com/p/introducing-valtio-reactive-a-reactive-library-built-on-valtio</link>
  <guid isPermaLink="true">https://newsletter.daishikato.com/p/introducing-valtio-reactive-a-reactive-library-built-on-valtio</guid>
  <pubDate>Wed, 02 Jul 2025 15:00:00 +0000</pubDate>
  <atom:published>2025-07-02T15:00:00Z</atom:published>
    <dc:creator>Daishi Kato</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><p class="paragraph" style="text-align:left;">Hi,</p><p class="paragraph" style="text-align:left;">Valtio is a proxy-based state management library for React—but it also works in plain JavaScript. Its primary goal is to provide a global-state solution for React, not to solve JavaScript reactivity in general. That said, its vanilla API remains quite useful outside React.</p><h3 class="heading" style="text-align:left;" id="valtio-in-vanilla-java-script">Valtio in Vanilla JavaScript</h3><p class="paragraph" style="text-align:left;">For example, you can subscribe to changes in a proxy state:</p><div class="codeblock"><pre><code>import &#123; proxy, subscribe &#125; from &#39;valtio/vanilla&#39;;

const state = proxy(&#123; count: 0 &#125;);
subscribe(state, () =&gt; &#123;
  console.log(&#39;Count changed:&#39;, state.count);
&#125;);

state.count++; // → &quot;Count changed: 1&quot;</code></pre></div><p class="paragraph" style="text-align:left;">And you can take snapshots of state over time:</p><div class="codeblock"><pre><code>import &#123; proxy, snapshot &#125; from &#39;valtio/vanilla&#39;;

const state = proxy(&#123; count: 0 &#125;);
const snap1 = snapshot(state);
state.count++;
const snap2 = snapshot(state);

console.log(snap1, snap2); // → &#123; count: 0 &#125; &#123; count: 1 &#125;</code></pre></div><p class="paragraph" style="text-align:left;">Snapshots are essential for React integration, but there are use cases in vanilla JavaScript, such as keeping a history of changes.</p><h3 class="heading" style="text-align:left;" id="whats-missing-compared-to-reactive-">What’s Missing Compared to “Reactive Frameworks”</h3><p class="paragraph" style="text-align:left;">I’m not very familiar with all the reactive frameworks, so please correct me if I’ve gotten anything wrong. What seems to be missing in Valtio, compared to other reactive frameworks, are two common patterns:</p><ol start="1"><li><p class="paragraph" style="text-align:left;"><b>Effects with usage tracking</b></p></li><li><p class="paragraph" style="text-align:left;"><b>Computed values with usage tracking</b></p></li></ol><h4 class="heading" style="text-align:left;" id="1-effects-with-usage-tracking">1. Effects with Usage Tracking</h4><p class="paragraph" style="text-align:left;">Currently, you subscribe by passing the state and a callback:</p><div class="codeblock"><pre><code>const state = proxy(&#123; count: 0 &#125;);
subscribe(state, () =&gt; &#123;
  console.log(&#39;Count changed:&#39;, state.count);
&#125;);</code></pre></div><p class="paragraph" style="text-align:left;">A reactive-style effect would track only the properties you access, without specifying the state object explicitly:</p><div class="codeblock"><pre><code>const state = proxy(&#123; count: 0 &#125;);
effect(() =&gt; &#123;
  console.log(&#39;Count changed:&#39;, state.count);
&#125;);

state.count++; // → &quot;Count changed: 1&quot;</code></pre></div><p class="paragraph" style="text-align:left;">This also supports multiple source states without extra arguments.</p><h4 class="heading" style="text-align:left;" id="2-computed-values-with-usage-tracki">2. Computed Values with Usage Tracking</h4><p class="paragraph" style="text-align:left;">Computed works similarly; while <code>effect</code> doesn’t return anything, <code>computed</code> returns a new proxy state. It looks like this:</p><div class="codeblock"><pre><code>const state = proxy(&#123; count: 0 &#125;);

const derived = computed(&#123;  
  double: () =&gt; state.count * 2,
&#125;);

console.log(derived.double); // → 0
state.count++;
console.log(derived.double); // → 2</code></pre></div><p class="paragraph" style="text-align:left;">Now, there’s a caveat. Because effects and computed values react immediately to changes, if we want to make multiple updates we need to batch them explicitly. For example:</p><div class="codeblock"><pre><code>batch(() =&gt; &#123;
  state.count++;
  state.count++;
&#125;);</code></pre></div><p class="paragraph" style="text-align:left;">Vanilla Valtio batches by waiting a macrotask, which works for React but not for these reactive primitives.</p><h3 class="heading" style="text-align:left;" id="introducing-valtioreactive">Introducing valtio-reactive</h3><p class="paragraph" style="text-align:left;">To fill these gaps, we built <b>valtio-reactive</b>. It implements <code>effect</code>, <code>computed</code>, and <code>batch</code> on top of Valtio:</p><div class="codeblock"><pre><code>npm install valtio-reactive</code></pre></div><p class="paragraph" style="text-align:left;">You can import them from the library:</p><div class="codeblock"><pre><code>import &#123; effect, computed, batch &#125; from &#39;valtio-reactive&#39;;</code></pre></div><p class="paragraph" style="text-align:left;">“valtio-reactive makes Valtio a reactive library.”</p><p class="paragraph" style="text-align:left;">If you’re curious, give it a try and share your feedback. While valtio-reactive isn’t tuned for performance, benchmarking will be interesting too.</p><p class="paragraph" style="text-align:left;">Happy coding.</p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=1dc9a68f-22c5-441a-9cd7-d9c9175fc227&utm_medium=post_rss&utm_source=daishi_kato_s_read_the_code">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>The Past and Future of Render Optimization with React Context</title>
  <description>From useContextSelector to use(store)</description>
  <link>https://newsletter.daishikato.com/p/the-past-and-future-of-render-optimization-with-react-context</link>
  <guid isPermaLink="true">https://newsletter.daishikato.com/p/the-past-and-future-of-render-optimization-with-react-context</guid>
  <pubDate>Tue, 20 May 2025 15:00:00 +0000</pubDate>
  <atom:published>2025-05-20T15:00:00Z</atom:published>
    <dc:creator>Daishi Kato</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><p class="paragraph" style="text-align:left;">Hi,</p><p class="paragraph" style="text-align:left;">First of all, this post is based on uncertainty. Please don’t take any of it too seriously—these are just thoughts and observations based on past work and recent updates from the React team.</p><h3 class="heading" style="text-align:left;" id="the-problem-state-and-context-in-re">The Problem: State and Context in React</h3><p class="paragraph" style="text-align:left;">Using <code>useState</code> and <code>useContext</code> for state management is still common today—and it works fine until you run into <b>Provider hell</b>. This happens when your component tree is wrapped in multiple context providers, and managing them becomes a chore.</p><p class="paragraph" style="text-align:left;">One workaround is to collapse multiple providers into a single component using <code>reduceRight</code>. For example:<br>🔗 <a class="link" href="https://x.com/dai_shi/status/1174093787137630210?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=the-past-and-future-of-render-optimization-with-react-context" target="_blank" rel="noopener noreferrer nofollow">Reference</a></p><div class="codeblock"><pre><code>const CombinedProviders = (props) =&gt; &#123;
  const providers = [
    [Provider1, &#123; value: props.value1 &#125;],
    [Provider2, &#123; value: props.value2 &#125;],
    [Provider3, &#123; value: props.value3 &#125;],
  ];
  return providers.reduceRight(
    (children, [Provider, value]) =&gt;
      &lt;Provider &#123;...value&#125;&gt;&#123;children&#125;&lt;/Provider&gt;,
    props.children
  );
&#125;;</code></pre></div><p class="paragraph" style="text-align:left;">This helps with composition, but not with <b>dynamic state</b>. If you add a new state and context to the tree, it still rerenders the entire subtree.</p><h3 class="heading" style="text-align:left;" id="the-first-solution-use-context-sele">The First Solution: <code>useContextSelector</code></h3><p class="paragraph" style="text-align:left;">To solve this, <a class="link" href="https://github.com/reactjs/rfcs/pull/119?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=the-past-and-future-of-render-optimization-with-react-context" target="_blank" rel="noopener noreferrer nofollow">RFC #119</a> proposed <code>useContextSelector</code>. Before that landed officially, I released a userland version as the <code>use-context-selector</code> package.</p><div class="codeblock"><pre><code>import &#123; createContext, useContextSelector &#125; from &#39;use-context-selector&#39;;

const context = createContext(null);

const Counter1 = () =&gt; &#123;
  const count1 = useContextSelector(context, (v) =&gt; v[0].count1);
  const setState = useContextSelector(context, (v) =&gt; v[1]);
  // ...
&#125;;</code></pre></div><p class="paragraph" style="text-align:left;">The main use case here was state. In some cases, that state is held in an external store.</p><h3 class="heading" style="text-align:left;" id="then-came-use-sync-external-store">Then Came <code>useSyncExternalStore</code></h3><p class="paragraph" style="text-align:left;">React introduced <code>useSyncExternalStore</code> as an official way to subscribe to external state safely in concurrent rendering:</p><div class="codeblock"><pre><code>import &#123; useSyncExternalStore &#125; from &#39;react&#39;;
import &#123; todosStore &#125; from &#39;./todoStore.js&#39;;

function TodosApp() &#123;
  const todos = useSyncExternalStore(
    todosStore.subscribe,
    todosStore.getSnapshot
  );
&#125;</code></pre></div><p class="paragraph" style="text-align:left;">But there’s a caveat: <code>useSyncExternalStore</code> is great for safe external state syncing, but it doesn’t always play well with <b>concurrent rendering</b>.<br>🔗 <a class="link" href="https://github.com/facebook/react/issues/26814?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=the-past-and-future-of-render-optimization-with-react-context" target="_blank" rel="noopener noreferrer nofollow">See this issue</a></p><h3 class="heading" style="text-align:left;" id="what-about-selectors">What About Selectors?</h3><p class="paragraph" style="text-align:left;">The React team explored context selector solutions but seemed reluctant to embrace selector-based APIs. (Incidentally, I developed <a class="link" href="https://jotai.org?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=the-past-and-future-of-render-optimization-with-react-context" target="_blank" rel="noopener noreferrer nofollow">Jotai</a> to avoid selectors while still optimizing rendering.)</p><p class="paragraph" style="text-align:left;">Instead, the team seems to prefer <b>composable patterns</b>, such as combining <code>useMemo</code> with <code>use(context)</code>. I built an experimental userland version using this idea:<br>🔗 <code>react18-use</code></p><div class="codeblock"><pre><code>import &#123; createContext, use, useMemo &#125; from &#39;react18-use&#39;;

const MyContext = createContext(&#123; foo: &#39;&#39;, count: 0 &#125;);

const Component = () =&gt; &#123;
  const foo = useMemo(() =&gt; &#123;
    const &#123; foo &#125; = use(MyContext);
    return foo;
  &#125;, []);
  return &lt;p&gt;Foo: &#123;foo&#125; (&#123;Math.random()&#125;)&lt;/p&gt;;
&#125;;</code></pre></div><p class="paragraph" style="text-align:left;">This approach may work better with <b>React Compiler</b>, and it’s certainly an interesting direction.</p><h3 class="heading" style="text-align:left;" id="looking-ahead-usestore">Looking Ahead: <code>use(store)</code></h3><p class="paragraph" style="text-align:left;">In a recent React blog post, the team introduced a mention of a new API: <code>use(store)</code>. It appears to be a concurrent-compatible variant of <code>useSyncExternalStore</code>.</p><div class="codeblock"><pre><code>const value = use(store);</code></pre></div><p class="paragraph" style="text-align:left;">We don’t know the details yet. But if it works as intended, I expect <code>use(store)</code> to take priority over <code>useMemo + use(context)</code> patterns—at least in many cases. The two solve different problems, but if the former is widely adopted, the latter might become a niche technique (except where React Compiler makes it particularly useful).</p><h3 class="heading" style="text-align:left;" id="in-conclusion">In Conclusion</h3><p class="paragraph" style="text-align:left;">We don’t know the future yet—these are just some ideas based on where things seem to be going. But it’s always exciting to explore the evolution of patterns in React.</p><p class="paragraph" style="text-align:left;">Happy coding.</p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=2bdf6ba5-29f5-4c07-8219-ad25c849e745&utm_medium=post_rss&utm_source=daishi_kato_s_read_the_code">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>A Simplified Version of Valtio</title>
  <description>What If the Proxy Only Handled Shallow State?</description>
  <link>https://newsletter.daishikato.com/p/a-simplified-version-of-valtio</link>
  <guid isPermaLink="true">https://newsletter.daishikato.com/p/a-simplified-version-of-valtio</guid>
  <pubDate>Sun, 18 May 2025 15:00:00 +0000</pubDate>
  <atom:published>2025-05-18T15:00:00Z</atom:published>
    <dc:creator>Daishi Kato</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><p class="paragraph" style="text-align:left;">Hi,</p><p class="paragraph" style="text-align:left;">A couple of years ago, I shared a simplified version of Jotai, which helped people understand the basic idea behind its implementation.<br>🔗 <a class="link" href="https://jotai.org/docs/guides/core-internals?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=a-simplified-version-of-valtio" target="_blank" rel="noopener noreferrer nofollow">Jotai Core Internals</a></p><p class="paragraph" style="text-align:left;">I think I haven’t done the same for Valtio—until now. Today, I came up with a simplified version of Valtio that only <b>shallowly</b> wraps the object in a proxy.</p><h3 class="heading" style="text-align:left;" id="but-wait-valtio-is-meant-for-deep-p">But Wait—Valtio Is Meant for Deep Proxies</h3><p class="paragraph" style="text-align:left;">To be clear, the <b>entire purpose</b> of <a class="link" href="https://valtio.dev?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=a-simplified-version-of-valtio" target="_blank" rel="noopener noreferrer nofollow">Valtio</a> is to support <b>deep proxies</b>, because that’s what’s needed to comply with React’s immutability contract.</p><p class="paragraph" style="text-align:left;">Still, simplifying the core idea can be helpful for learning. So here’s a version that only proxies the top level:</p><h3 class="heading" style="text-align:left;" id="the-simplified-implementation">The Simplified Implementation</h3><div class="codeblock"><pre><code>const SNAPSHOT = Symbol();
const LISTENERS = Symbol();

export const proxy = (baseObj) =&gt; &#123;
  let snap = &#123; ...baseObj &#125;;
  const listeners = new Set();
  return new Proxy(baseObj, &#123;
    set(target, prop, value, receiver) &#123;
      const result = Reflect.set(target, prop, value, receiver);
      snap = &#123; ...target &#125;;
      listeners.forEach((fn) =&gt; fn());
      return result;
    &#125;,
    get(target, prop, receiver) &#123;
      if (prop === SNAPSHOT) &#123;
        return snap;
      &#125;
      if (prop === LISTENERS) &#123;
        return listeners;
      &#125;
      return Reflect.get(target, prop, receiver);
    &#125;,
  &#125;);
&#125;;

export const snapshot = (p) =&gt; p[SNAPSHOT];

export const subscribe = (p, fn) =&gt; &#123;
  const listeners = p[LISTENERS];
  listeners.add(fn);
  return () =&gt; listeners.delete(fn);
&#125;;

import &#123; useCallback, useSyncExternalStore &#125; from &#39;react&#39;;

export const useSnapshot = (p) =&gt;
  useSyncExternalStore(
    useCallback((fn) =&gt; subscribe(p, fn), [p]),
    () =&gt; snapshot(p),
  );</code></pre></div><h3 class="heading" style="text-align:left;" id="a-quick-note">A Quick Note</h3><p class="paragraph" style="text-align:left;">I haven’t tested this code, so don’t be surprised if it has bugs. Feel free to try it out and fix whatever doesn’t work.</p><p class="paragraph" style="text-align:left;">Happy coding.</p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=cc47a260-1cbd-4d08-9e07-171fe582c8f3&utm_medium=post_rss&utm_source=daishi_kato_s_read_the_code">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>Emulating Slow Network in Playwright</title>
  <description>A Use Case from Waku&#39;s E2E Tests</description>
  <link>https://newsletter.daishikato.com/p/emulating-slow-network-in-playwright</link>
  <guid isPermaLink="true">https://newsletter.daishikato.com/p/emulating-slow-network-in-playwright</guid>
  <pubDate>Sat, 10 May 2025 15:13:00 +0000</pubDate>
  <atom:published>2025-05-10T15:13:00Z</atom:published>
    <dc:creator>Daishi Kato</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><p class="paragraph" style="text-align:left;">Hi,</p><p class="paragraph" style="text-align:left;">I&#39;ve been developing <b>Waku</b>, a React framework, for a couple of years now. It started as my personal project and is now a team effort to explore React Server Components. Check it out: <a class="link" href="https://waku.gg?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=emulating-slow-network-in-playwright" target="_blank" rel="noopener noreferrer nofollow">waku.gg</a></p><h3 class="heading" style="text-align:left;" id="why-i-wanted-to-simulate-a-slow-net">Why I Wanted to Simulate a Slow Network</h3><p class="paragraph" style="text-align:left;">We use <a class="link" href="https://playwright.dev/?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=emulating-slow-network-in-playwright" target="_blank" rel="noopener noreferrer nofollow">Playwright</a> for end-to-end (E2E) testing in Waku. Ideally, E2E tests <b>should avoid relying on timeouts</b>, and instead wait for specific conditions or signals. But while debugging a feature, I needed to simulate a <b>slow network</b>—specifically to test a pending state handled by <code>useTransition</code>.</p><p class="paragraph" style="text-align:left;">Fortunately, there’s a simple way to do this in Playwright, which I’ll share today.</p><h3 class="heading" style="text-align:left;" id="the-solution">The Solution</h3><p class="paragraph" style="text-align:left;">Here’s the code we use:<br>🔗 <a class="link" href="https://github.com/wakujs/waku/blob/a35e3ef48532d45b5c3b37dbe97d5fc7d0f4a7b8/e2e/rsc-basic.spec.ts?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=emulating-slow-network-in-playwright#L87-L90" target="_blank" rel="noopener noreferrer nofollow">View on GitHub</a></p><div class="codeblock"><pre><code>await page.route(/.*\/RSC\/.*/, async (route) =&gt; &#123;
  await new Promise((r) =&gt; setTimeout(r, 100));
  await route.continue();
&#125;);</code></pre></div><p class="paragraph" style="text-align:left;">This doesn’t truly slow down the network, but it <b>adds a delay</b> for matching routes. With this, the tests run more stably and let me observe pending UI states more reliably.</p><h3 class="heading" style="text-align:left;" id="a-note-on-routing-patterns">A Note on Routing Patterns</h3><p class="paragraph" style="text-align:left;">Initially, my attempt didn’t work. I tried something like:</p><div class="codeblock"><pre><code>await page.route(&#39;/RSC/**&#39;, async (route) =&gt; &#123;</code></pre></div><p class="paragraph" style="text-align:left;">This probably didn’t match the intended URL, though I’m not exactly sure why. I haven’t figured out a good way to debug this pattern matching yet—suggestions are welcome!</p><h3 class="heading" style="text-align:left;" id="looking-ahead">Looking Ahead</h3><p class="paragraph" style="text-align:left;">We’re planning to add more E2E tests to the Waku repository. If you’re interested in contributing, you’re very welcome!</p><p class="paragraph" style="text-align:left;">Happy coding.</p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=46350d4d-1f84-485c-9bed-cfd0a99d5531&utm_medium=post_rss&utm_source=daishi_kato_s_read_the_code">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>React Native Confusion with Newer Versions</title>
  <description>Behavioral Change with Module Resolution</description>
  <link>https://newsletter.daishikato.com/p/react-native-confusion-with-newer-versions</link>
  <guid isPermaLink="true">https://newsletter.daishikato.com/p/react-native-confusion-with-newer-versions</guid>
  <pubDate>Thu, 01 May 2025 15:00:00 +0000</pubDate>
  <atom:published>2025-05-01T15:00:00Z</atom:published>
    <dc:creator>Daishi Kato</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><p class="paragraph" style="text-align:left;">Hi,</p><p class="paragraph" style="text-align:left;">This might be a well-known issue in the React Native community, but recent versions have changed the behavior of module resolution. Don&#39;t get me wrong—it’s generally a good move.</p><hr class="content_break"><h3 class="heading" style="text-align:left;" id="metro-and-the-exports-field">Metro and the <code>&quot;exports&quot;</code> Field</h3><p class="paragraph" style="text-align:left;">Previously, Metro (the bundler used in React Native) didn&#39;t support the <code>&quot;exports&quot;</code> field in <code>package.json</code>. It was only available with the opt-in flag <code>unstable_enablePackageExports</code>.</p><p class="paragraph" style="text-align:left;">With this flag enabled, Metro starts to understand and respect the <code>&quot;exports&quot;</code> field.</p><p class="paragraph" style="text-align:left;">Here’s how it looks in Zustand’s <code>package.json</code>:<br>🔗 <a class="link" href="https://github.com/pmndrs/zustand/blob/48985a4cc2284b2587d01272a47a124067637b12/package.json?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=react-native-confusion-with-newer-versions#L27-L49" target="_blank" rel="noopener noreferrer nofollow">View on GitHub</a></p><div class="codeblock"><pre><code>&quot;exports&quot;: &#123;
  &quot;./package.json&quot;: &quot;./package.json&quot;,
  &quot;.&quot;: &#123;
    &quot;import&quot;: &#123;
      &quot;types&quot;: &quot;./esm/index.d.mts&quot;,
      &quot;default&quot;: &quot;./esm/index.mjs&quot;
    &#125;,
    &quot;default&quot;: &#123;
      &quot;types&quot;: &quot;./index.d.ts&quot;,
      &quot;default&quot;: &quot;./index.js&quot;
    &#125;
  &#125;,
  &quot;./*&quot;: &#123;
    &quot;import&quot;: &#123;
      &quot;types&quot;: &quot;./esm/*.d.mts&quot;,
      &quot;default&quot;: &quot;./esm/*.mjs&quot;
    &#125;,
    &quot;default&quot;: &#123;
      &quot;types&quot;: &quot;./*.d.ts&quot;,
      &quot;default&quot;: &quot;./*.js&quot;
    &#125;
  &#125;
&#125;</code></pre></div><p class="paragraph" style="text-align:left;">Roughly speaking:</p><ul><li><p class="paragraph" style="text-align:left;">When the <code>import</code> condition is met, the bundler picks the ESM build.</p></li><li><p class="paragraph" style="text-align:left;">Otherwise, it falls back to the CJS build.</p></li><li><p class="paragraph" style="text-align:left;">If a bundler doesn’t understand the <code>&quot;exports&quot;</code> field at all, it defaults to using CJS.</p></li></ul><hr class="content_break"><h3 class="heading" style="text-align:left;" id="the-hermes-and-importmeta-problem">The Hermes and <code>import.meta</code> Problem</h3><p class="paragraph" style="text-align:left;">The issue arises because the most-used JavaScript runtime in React Native—Hermes—still does not fully support ESM. It throws an error when encountering <code>import.meta</code>.</p><p class="paragraph" style="text-align:left;">🔗 <a class="link" href="https://github.com/pmndrs/zustand/discussions/1967?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=react-native-confusion-with-newer-versions" target="_blank" rel="noopener noreferrer nofollow">Zustand discussion #1967</a></p><p class="paragraph" style="text-align:left;">My hope was that Hermes would support <code>import.meta</code> before <code>unstable_enablePackageExports</code> became stable.</p><p class="paragraph" style="text-align:left;">Unfortunately, that didn&#39;t happen.</p><p class="paragraph" style="text-align:left;">Now it seems that <code>enablePackageExports</code> is enabled by default, but Hermes still errors on <code>import.meta</code>.</p><hr class="content_break"><h3 class="heading" style="text-align:left;" id="the-workaround">The Workaround</h3><p class="paragraph" style="text-align:left;">From the discussion, I concluded that using the ESM build in React Native is either a bad idea or simply too early. As a workaround, I added a new condition in the <code>exports</code> field specifically for React Native users.</p><p class="paragraph" style="text-align:left;">🔗 <a class="link" href="https://github.com/pmndrs/zustand/pull/3087?utm_source=newsletter.daishikato.com&utm_medium=newsletter&utm_campaign=react-native-confusion-with-newer-versions" target="_blank" rel="noopener noreferrer nofollow">Zustand PR #3087</a></p><hr class="content_break"><h3 class="heading" style="text-align:left;" id="final-thoughts">Final Thoughts</h3><p class="paragraph" style="text-align:left;">What’s concerning is that my original plan was to eventually drop CJS and fully move to ESM. But that now seems like a bad idea if the entire React Native ecosystem still relies on CJS.</p><p class="paragraph" style="text-align:left;">Happy coding.</p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=54c09fb7-9d0b-470a-bbfd-16312b454b8e&utm_medium=post_rss&utm_source=daishi_kato_s_read_the_code">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

      <item>
  <title>Tricky Behavior with Proxy State</title>
  <description>A Case in Valtio</description>
  <link>https://newsletter.daishikato.com/p/tricky-behavior-with-proxy-state</link>
  <guid isPermaLink="true">https://newsletter.daishikato.com/p/tricky-behavior-with-proxy-state</guid>
  <pubDate>Mon, 21 Apr 2025 15:00:00 +0000</pubDate>
  <atom:published>2025-04-21T15:00:00Z</atom:published>
    <dc:creator>Daishi Kato</dc:creator>
  <content:encoded><![CDATA[
    <div class='beehiiv'><style>
  .bh__table, .bh__table_header, .bh__table_cell { border: 1px solid #C0C0C0; }
  .bh__table_cell { padding: 5px; background-color: #FFFFFF; }
  .bh__table_cell p { color: #2D2D2D; font-family: 'Helvetica',Arial,sans-serif !important; overflow-wrap: break-word; }
  .bh__table_header { padding: 5px; background-color:#F1F1F1; }
  .bh__table_header p { color: #2A2A2A; font-family:'Trebuchet MS','Lucida Grande',Tahoma,sans-serif !important; overflow-wrap: break-word; }
</style><div class='beehiiv__body'><p class="paragraph" style="text-align:left;">Hi,</p><p class="paragraph" style="text-align:left;">I’d like to share something I encountered today. A new discussion was posted in the Valtio repository about an unexpected behavior. It turns out to be a kind of limitation—due to the nature of proxies or the way we use them.</p><hr class="content_break"><h3 class="heading" style="text-align:left;" id="a-simple-example-without-proxies">A Simple Example Without Proxies</h3><p class="paragraph" style="text-align:left;">Let’s start with a plain object example:</p><div class="codeblock"><pre><code>const o = &#123;&#125;;
const x = (o.x ||= &#123;&#125;);
console.log(x === o.x); // ---&gt; true</code></pre></div><p class="paragraph" style="text-align:left;">The idea here is to initialize <code>x</code> if it hasn’t been set yet, and use it in either case. As the last line shows, <code>x</code> and <code>o.x</code> refer to the same object.</p><hr class="content_break"><h3 class="heading" style="text-align:left;" id="now-with-proxies">Now With Proxies</h3><p class="paragraph" style="text-align:left;">Things get more interesting when we introduce a proxy. Suppose we use a <code>set</code> handler to wrap any assigned value in another proxy:</p><div class="codeblock"><pre><code>const p = new Proxy(&#123;&#125;, &#123;
  set(target, key, value) &#123;
    target[key] = new Proxy(value, &#123;&#125;);
    return true;
  &#125;
&#125;);
const y = (p.y ||= &#123;&#125;);
console.log(y === p.y); // ---&gt; false</code></pre></div><p class="paragraph" style="text-align:left;">Here’s where it gets tricky: we expect the proxy to behave transparently, but it doesn’t.<br>The variable <code>y</code> and <code>p.y</code> are <b>not</b> the same object. Why? Because the expression <code>(p.y ||= &#123;&#125;)</code> does <b>not</b> re-access <code>p.y</code> after the assignment. So the value of <code>y</code> is the raw <code>&#123;&#125;</code>, while <code>p.y</code> is the proxied version.</p><hr class="content_break"><h3 class="heading" style="text-align:left;" id="re-evaluating-the-expression">Re-Evaluating the Expression</h3><p class="paragraph" style="text-align:left;">If we evaluate the same expression again, it behaves as expected:</p><div class="codeblock"><pre><code>const y2 = (p.y ||= &#123;&#125;);
console.log(y2 === p.y); // ---&gt; true</code></pre></div><p class="paragraph" style="text-align:left;">Now that <code>p.y</code> is no longer <code>undefined</code>, the expression simply returns <code>p.y</code>, which is already wrapped with a proxy.</p><hr class="content_break"><h3 class="heading" style="text-align:left;" id="final-thoughts">Final Thoughts</h3><p class="paragraph" style="text-align:left;">While this behavior is understandable—especially if you know how proxies work—it’s definitely a little tricky. Explaining it without going into proxy internals can be hard.</p><p class="paragraph" style="text-align:left;">Happy coding.</p></div><div class='beehiiv__footer'><br class='beehiiv__footer__break'><hr class='beehiiv__footer__line'><a target="_blank" class="beehiiv__footer_link" style="text-align: center;" href="https://www.beehiiv.com/?utm_campaign=2d616e9c-ff34-4e69-8124-959423cb4b61&utm_medium=post_rss&utm_source=daishi_kato_s_read_the_code">Powered by beehiiv</a></div></div>
  ]]></content:encoded>
</item>

  </channel>
</rss>
