<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Toru Kobayashi on Medium]]></title>
        <description><![CDATA[Stories by Toru Kobayashi on Medium]]></description>
        <link>https://medium.com/@koba04?source=rss-4a249aae4618------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*7SgWWjSHf2hKM67S.jpeg</url>
            <title>Stories by Toru Kobayashi on Medium</title>
            <link>https://medium.com/@koba04?source=rss-4a249aae4618------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Thu, 09 Apr 2026 00:16:44 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@koba04/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Custom heading ids for translation]]></title>
            <link>https://koba04.medium.com/custom-heading-ids-for-translation-9a6f92cce1e8?source=rss-4a249aae4618------2</link>
            <guid isPermaLink="false">https://medium.com/p/9a6f92cce1e8</guid>
            <category><![CDATA[translation]]></category>
            <category><![CDATA[documentation]]></category>
            <category><![CDATA[markdown]]></category>
            <dc:creator><![CDATA[Toru Kobayashi]]></dc:creator>
            <pubDate>Tue, 02 May 2023 14:51:51 GMT</pubDate>
            <atom:updated>2023-05-02T14:51:51.265Z</atom:updated>
            <content:encoded><![CDATA[<p>Have you ever read translated documents for OSS libraries? If so, did the links with hash fragment (#id) work as expected? That’s the topic of this post.</p><p>I’m maintaining some translations for OSS libraries like React, SWR.</p><ul><li><a href="https://ja.react.dev/">https://ja.react.dev/</a></li><li><a href="https://swr.vercel.app/ja">https://swr.vercel.app/ja</a></li></ul><p>There is a difference between the docs. The links with hash fragment in the Japanese React docs work, but the links in the Japanese SWR docs don’t work even if the English version works as expected. Why?</p><p>The reason is that their heading ids are also translated.</p><p>For example, SWR has a link like <a href="https://swr.vercel.app/docs/revalidation#disable-automatic-revalidations">https://swr.vercel.app/docs/revalidation#disable-automatic-revalidations</a> .</p><p>#disable-automatic-revalidations is a hash fragment that points to a specific heading on the page.</p><p>The heading title is “Disable Automatic Revalidations”. The heading id is converted from the heading title.</p><p>Disable Automatic Revalidations -&gt; #disable-automatic-revalidations</p><p>The markup is the following.</p><pre>&lt;h2 class=&quot;...&quot;&gt;<br>　Disable Automatic Revalidations<br>　&lt;span class=&quot;...&quot; id=&quot;disable-automatic-revalidations&quot;&gt;&lt;/span&gt;<br>  &lt;a href=&quot;#disable-automatic-revalidations&quot; class=&quot;subheading-anchor&quot; aria-label=&quot;Permalink for this section&quot;&gt;&lt;/a&gt;<br>&lt;/h2&gt;</pre><p>That’s great! Let’s see the Japanese version.</p><p>The link is <a href="https://swr.vercel.app/ja/docs/revalidation#%E8%87%AA%E5%8B%95%E5%86%8D%E6%A4%9C%E8%A8%BC%E3%81%AE%E7%84%A1%E5%8A%B9%E5%8C%96">https://swr.vercel.app/ja/docs/revalidation#%E8%87%AA%E5%8B%95%E5%86%8D%E6%A4%9C%E8%A8%BC%E3%81%AE%E7%84%A1%E5%8A%B9%E5%8C%96</a>, which is URL encoded and decoded text is “自動再検証の無効化”.</p><p>The markup is like this.</p><pre>&lt;h2 class=...&quot;&gt;<br>  自動再検証の無効化<br>  &lt;span class=&quot;...&quot; id=&quot;自動再検証の無効化&quot;&gt;<br>  &lt;/span&gt;&lt;a href=&quot;#自動再検証の無効化&quot; class=&quot;subheading-anchor&quot; aria-label=&quot;Permalink for this section&quot;&gt;&lt;/a&gt;<br>&lt;/h2&gt;</pre><p>The heading ids are also translated because it’s based on the heading title. This don’t work because we don’t modify hash fragments for translated docs, which means we still the links like <a href="https://swr.vercel.app/ja/docs/revalidation#disable-automatic-revalidations">https://swr.vercel.app/ja/docs/revalidation#disable-automatic-revalidations</a> that doesn’t match with any heading ids.</p><p>So we have to keep the heading ids original.</p><p><a href="https://nextra.site/">Nextra</a>, a site generator framework that SWR uses, has a feature for it.</p><p><a href="https://nextra.site/docs/guide/markdown#custom-heading-id">Markdown - Nextra</a></p><p>So I’ve made a PR to fix this.</p><p><a href="https://github.com/vercel/swr-site/pull/489">fix: all broken links with hash fragment by adding heading ids by koba04 · Pull Request #489 · vercel/swr-site</a></p><p>This PR adds custom ids to all headings in the docs.</p><pre>- ## Optimistic UI<br>+ ## Optimistic UI [#optimistic-ui]</pre><p>You can see the script that I used to make the PR.</p><p><a href="https://github.com/koba04/convert-swr-site-heading-ids">GitHub - koba04/convert-swr-site-heading-ids: This adds ids to all headings in the SWR site</a></p><p>React Docs has the same feature, which is a different syntax, as a remark plugin.</p><p><a href="https://github.com/reactjs/react.dev/blob/main/plugins/remark-header-custom-ids.js">react.dev/remark-header-custom-ids.js at main · reactjs/react.dev</a></p><pre>## Using React for an entire subroute of your existing website {/*using-react-for-an-entire-subroute-of-your-existing-website*/}</pre><p>This is a common pitfall for translation projects, and it’s annoying for users. So I hope this helps some projects have translations.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9a6f92cce1e8" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Organize SWR Cache with Tag]]></title>
            <link>https://koba04.medium.com/organize-swr-cache-with-tag-33d5b1aac3bd?source=rss-4a249aae4618------2</link>
            <guid isPermaLink="false">https://medium.com/p/33d5b1aac3bd</guid>
            <category><![CDATA[swr]]></category>
            <category><![CDATA[react]]></category>
            <dc:creator><![CDATA[Toru Kobayashi]]></dc:creator>
            <pubDate>Sun, 16 Apr 2023 15:46:56 GMT</pubDate>
            <atom:updated>2023-04-16T15:46:56.340Z</atom:updated>
            <content:encoded><![CDATA[<p>This post explains a pattern using tags with SWR. It’s a technique to manage the SWR cache well organized.</p><h3>Key in SWR</h3><p>Do you know SWR accepts a non-string values as its key?<br>Many examples in the SWR website use URL strings as keys, but you can pass various types as the key, like an array or an object.</p><pre>useSWR(`/api/user/{userId}`, fetcher)<br>// or<br>useSWR([&quot;user&quot;, userId], fetcher)<br>// or<br>useSWR({ path: &quot;/api/user&quot;, userId }, fetcher)</pre><p>In this post, I’ll introduce a pattern combining non-string keys and Mutate Filter Function, which is added in v2.</p><h3>Mutate Filter Function</h3><p>Mutate Filter Function is a feature to mutate multiple keys based on a filter function, which is passed as the first argument of a global mutate function.<br>The filter function is applied to all cache keys, and all cache data that the filter function returns true are mutated.</p><p>You can see more details in the documentation.</p><p><a href="https://swr.vercel.app/docs/mutation#mutate-multiple-items">https://swr.vercel.app/docs/mutation#mutate-multiple-items</a></p><p>For example, you can mutate all keys starting with /api/user like this.<br>(If you are not familiar with the mutate function, check <a href="https://swr.vercel.app/docs/mutation">the documentation</a>.</p><pre>// You must use the `mutate` function instead of the bound `mutate`<br>const { mutate } = useSWRConfig()<br>// or import { mutate } from &quot;swr&quot;<br><br>// You shouldn&#39;t rely on the assumption that the key is a string<br>// because this function is applied to all cache keys.<br>mutate(key =&gt; typeof key === &quot;string&quot; &amp;&amp; key.startsWith(&quot;/api/user&quot;);</pre><p>In some cases, cache data have a relation with each other. For example, cache data for /api/users and /api/user/1 share the same data even though they are stored in the cache separately.</p><pre>// useSWR(&quot;/api/users, fetchAllUsers);<br>// cache: /api/users<br>[<br> { id: 1, name: &quot;John&quot;, score: 10 }, // 👀<br> { id: 2, name: &quot;Anna&quot;, score: 20 },<br> { id: 3, name: &quot;Tim&quot;, score: 30 }<br>]<br><br>// useSWR(&quot;/api/user/1&quot;, fetchUser);<br>// cache: /api/user/1<br>{ id: 1, name: &quot;John&quot;, score: 10 } // 👀</pre><p>In this case, we should update the both cache data when the user score has been updated.</p><pre>mutate(&quot;/api/user/1&quot;, updateUser);<br>// PUT /api/user/1 { score: 15 }<br><br>// cache: /api/user/1<br>{ id: 1, name: &quot;John&quot;, score: 15 }<br><br>// You should also update `/api/users`<br>mutate(&quot;/api/users&quot;, updatedUsers, { revalidate: false });<br><br>// cache: /api/users<br>[<br> { id: 1, name: &quot;John&quot;, score: 15 },<br> { id: 2, name: &quot;Anna&quot;, score: 20 },<br> { id: 3, name: &quot;Tim&quot;, score: 30 }<br>]</pre><p>If you didn’t update the cache data for /api/users, we would see stale data (score: 10).</p><p>In this example, we must recognize that api/user/1 and /api/users share the same data.<br>If the application gets scaled, this would be hard to maintain.</p><p>In order to manage the relation easily, let’s combine with Mutate Filter Function and non-string keys.</p><h3>Tagged Key</h3><p>As I mentioned before, the key of SWR accepts an object as its key, so you can introduce a concept like tags with the key. The tag is just a concept, not a feature.</p><p>In this post, I define the following shape of the key as an example.</p><pre>type Key = {<br> tags: string[],<br> path: string<br>};</pre><p>This is just an example, so I define the shape very simply. But you can define any shape of key for your application.</p><p>Let’s use the shape of the key, so useSWR calls would look like this.</p><pre>const userId = 1;<br>useSWR(<br>  {<br>    tags: [&quot;#user&quot;],<br>    path: &quot;/api/users&quot;<br>  },<br>  ({ path }) =&gt; fetcher(path)<br>);<br>useSWR(<br>  {<br>    tags: [&quot;#user&quot;, `#userId:${userId}`],<br>    path: `/api/users/${userId}`<br>  },<br>  ({ path }) =&gt; fetcher(path)<br>);</pre><p>That might be a bit more complex than using an URL string as its key, but it’s still straightforward.</p><p>Next, let’s define functions to take advantage of the tag.</p><p>The following is a function to revalidate all users’ data.</p><pre>const revalidateUsers = () =&gt;<br>  mutate(key =&gt;<br>    typeof key === &quot;object&quot; &amp;&amp;<br>     Array.isArray(key.tags) &amp;&amp;<br>     key.tags.includes(&quot;#user&quot;)<br>)</pre><p>This mutates all cache data having #user as a tag value. Of course, you should check the shape of the key before using the tag.</p><p>The following is a function to revalidate a specific user.</p><pre>const revalidateUsers = userId =&gt;<br>  mutate(key =&gt;<br>    typeof key === &quot;object&quot; &amp;&amp;<br>     Array.isArray(key.tags) &amp;&amp;<br>     key.tags.includes(&quot;#user&quot;) &amp;&amp;<br>     key.tags.includes(`#userId:${userId}`)<br>)</pre><p>This mutates all cache data having #user and a specific user id as tag values.</p><p>When you want to clear cache data rather than revalidating it, you can do it like this.</p><pre>const clearUsersData = () =&gt;<br>  mutate(<br>    key =&gt;<br>      typeof key === &quot;object&quot; &amp;&amp;<br>      Array.isArray(key.tags) &amp;&amp;<br>      key.tags.includes(&quot;#user&quot;),<br>    undefined,<br>    {<br>      revalidate: false<br>    }<br>)</pre><p>This clears all cache data having #user as a tag value.</p><p>You still have to manage the relation between each cache data, but the tag makes it more explicit.</p><h3>Limitation</h3><p>useSWRInfinite and useSWRSubscription store cache data that are not listed Mutate Filter Function.</p><p>ref. <a href="https://github.com/vercel/swr/issues/2497">https://github.com/vercel/swr/issues/2497</a></p><p>Note: You can update the useSWRInfinite cache with the global mutate function with the unstable way.</p><p><a href="https://swr.vercel.app/docs/pagination#global-mutate-with-useswrinfinite">https://swr.vercel.app/docs/pagination#global-mutate-with-useswrinfinite</a></p><h3>Conclusion</h3><p>If your application is getting complex and you have to manage many cache data related to each other, organizing cache keys like this might help you.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=33d5b1aac3bd" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Introduce SWR v2 and SWRDevTools]]></title>
            <link>https://koba04.medium.com/introduce-swr-v2-and-swrdevtools-d1c2ea4198dd?source=rss-4a249aae4618------2</link>
            <guid isPermaLink="false">https://medium.com/p/d1c2ea4198dd</guid>
            <dc:creator><![CDATA[Toru Kobayashi]]></dc:creator>
            <pubDate>Fri, 23 Dec 2022 16:24:08 GMT</pubDate>
            <atom:updated>2022-12-23T16:24:08.044Z</atom:updated>
            <content:encoded><![CDATA[<p>SWR v2 has been released in Dec 2022, which includes many features and improvements like the following.</p><ul><li>NewuseSWRMutation hook</li><li>Mutate multiple items feature</li><li>New preload API</li><li>New isLoading state</li><li>New keepPreviousData option</li><li>Improve Optimistic Updates support</li><li>Improve React 18 support</li><li>SWRDevTools</li></ul><p>You can check these updates in the blog post. These features improve user experiences of your application and developer experiences of your team.</p><p><a href="https://swr.vercel.app/blog/swr-v2">Announcing SWR 2.0 - SWR</a></p><p>In this post, I’ll focus on some of the updates.</p><h3>Mutate Multiple Items</h3><p>I’d say this was the biggest missing feature for SWR v1.</p><p>The global mutate API now accepts a filter function as its first argument.</p><p><a href="https://swr.vercel.app/docs/mutation#mutate-multiple-items">Mutation &amp; Revalidation - SWR</a></p><p>This gives us flexibility for mutation scenarios. Let’s take a look at examples.</p><p><strong>Revalidate all cache data for the same API endpoint with different query params</strong></p><p>For example, you have an API /api/users/?sort={id, name, etc}that returns users data, which accepts a sort key. When you have updated a user, you would want to revalidate all cache data for /api/users/ regardless of the sort key. The Mutate Multiple Items makes this possible.</p><pre>import { mutate } from &quot;swr&quot;;<br><br>const handleUpdateUser = async (user) =&gt; {<br>    await updateUser(user);<br>    // revalidate all cache data its key is start with /api/users<br>    mutate(key =&gt; typeof key === &quot;string&quot; &amp;&amp; key.startWith(&quot;/api/users/&quot;));<br>    // If you don&#39;t want to relivadate all keys and just want to invalidate the cache data,<br>    mutate(<br>      key =&gt; typeof key === &quot;string&quot; &amp;&amp; key.startWith(&quot;/api/users/&quot;),<br>      undefined,<br>      { revalidate: false }<br>    )<br>}</pre><p><strong>Revalidate the specific cache data of which keys are tagged arrays</strong></p><p>SWR allows us to use an array as the key, which means you can add a tag into each key.</p><pre>// [&#39;user&#39;, 1]<br>// [&#39;user&#39;, 2]<br>// [&#39;item&#39;, 1]</pre><p>We can update all cache data that have the same tag by the Mutate Multiple Items.</p><pre>// Revalidate all cache data of which tag is &quot;user&quot;<br>mutate(key =&gt; Array.isArray(key) &amp;&amp; key[0] === &quot;user&quot;);</pre><p>The filter function is applied to all cache keys, so you have to check the type of each cache key.</p><p>The Mutate Multiple Items gives us more flexible key management.</p><p><strong>Clear all cache data</strong></p><p>The Mutate Multiple Items can also use to clear all cache data.</p><pre>const clearCache = () =&gt; mutate(<br>  () =&gt; true,<br>  undefined,<br>  { revalidate: false }<br>)<br><br>// ...clear cache on logout<br>clearCache()</pre><p>You might wonder why we shouldn’t clear the cache data directly by accessing the cache object. Updating cache data directly might cause inconsistency in some scenarios like concurrent features or race conditions. So you should avoid it and use mutate instead.</p><h3>Documentation</h3><p>I think documentation is crucial for libraries. Developers can’t find a feature or might use it the wrong way when it’s not well documented. In the v2 release, We’ve reorganized some documentation, like <a href="https://swr.vercel.app/docs/mutation">the Mutation page</a>. I’ve also added a new “<a href="https://swr.vercel.app/docs/advanced/understanding">Understanding SWR</a>” page so that developers can understand how SWR behaves.</p><figure><img alt="The preview of the Understanding SWR page" src="https://cdn-images-1.medium.com/max/1024/1*qq82lHLrEO8IIai2Psh7dA.png" /><figcaption>Diagrams in the Understanding SWR page</figcaption></figure><p>This is from my past experience. When I started trying SWR, I was very confused about how to combine return values, which are data, isValidating, and error. SWR v2 introduces more patterns with isLoading and the keepPreviousData option. I think developers get more confused with them. In order to help understand this, I’ve added the new page based on the diagrams Shu created.</p><h3>Bundle Size and Optimization</h3><p>As you can see, SWR v2 has many features, but the bundle size is smaller than v1! The reason is that we’ve updated the build target version from ES5 to ES2018, which drastically reduced the bundle size. It also brings performance improvements with SSR.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bRypBjQbXbf7Yf8euT7N7w.png" /><figcaption>SWR v2 keeps the bundle size small</figcaption></figure><p><a href="https://bundlephobia.com/package/swr@2.0.0">swr ❘ Bundlephobia</a></p><h3>Middleware abstraction</h3><p>This is about internal implementation, so you don’t have to care about that. But I wanted to pick up that because I was impressed the power of abstraction. SWR introduced Middleware in the v1 release, which enables us to extend SWR in user land. But this is also beneficial for SWR itself.</p><p><a href="https://swr.vercel.app/blog/swr-v1#middleware">Announcing SWR 1.0 - SWR</a></p><p>For example, useSWRMutation, preload are implemented as a middleware, so we separate these implementation from core implementation of SWR, which keeps core implementation small. I think it’s important for us to keep adding new features to SWR. useSWRInfinite and useSWRImmutable are also implemented as middleware. you can check it on the GitHub.</p><p><a href="https://github.com/vercel/swr">https://github.com/vercel/swr</a></p><h3>SWRDevTools</h3><p>DevTools is a long standing issue for SWR, so I started implementing it because it seems to be fun 😁 I’m honored that SWRDevTools is a part of features of v2 release.</p><p><a href="https://swr-devtools.vercel.app/">https://swr-devtools.vercel.app/</a></p><p>This is the my first browser extension, so I’ve learned a lot of thing like this.</p><ul><li>How to develop and debug a extension</li><li>How to inject a script into a web page</li><li>How to add a panel to the developer tools</li><li>How to communicate between a webpage, a content script, a background script, and a devtool panel</li><li>How to implement a browser extension that works on Chrome (MV3) and Firefox (MV2)</li></ul><p>SWR v2 has a native support of SWRDevTools, so you don’t have to do any setup in your application. SWRDevTools has also support SWR v1. When you want to use SWRDevTools for SWR v1, you have to wrap your application into the SWRDevTools component.</p><p>I’ve also build a demo on the webpage so that developers can try SWRDevTools without installing the extension. This is also implemented by using SWRDevTools. This brings additional complexity into it, but that makes sense.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ao6bEtuEx2w50BJ1qYGbhQ.png" /><figcaption>The online demo of SWRDevTools on the website</figcaption></figure><p>I hope SWRDevTools helps your development.</p><h3>Thank you!</h3><p>You can check other great features on the blog post and documentation!</p><p>I’ve learned a lot of things through working on the v2 release. All of the core member of SWR are great. Thank you for working with me!</p><figure><img alt="The Author’s of SWR v2 blog" src="https://cdn-images-1.medium.com/max/1024/1*tkXRoYaOFKbJABBzx-ObkQ.png" /><figcaption>I’m very honored to be listed as a author</figcaption></figure><figure><img alt="Thanks message to me" src="https://cdn-images-1.medium.com/max/1024/1*wBc4dxFu4oaBtekkxeDv7g.png" /><figcaption>Thank you too!</figcaption></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d1c2ea4198dd" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Revalidating options of SWR]]></title>
            <link>https://koba04.medium.com/revalidating-options-of-swr-4d9f08bee813?source=rss-4a249aae4618------2</link>
            <guid isPermaLink="false">https://medium.com/p/4d9f08bee813</guid>
            <category><![CDATA[swr]]></category>
            <category><![CDATA[react]]></category>
            <dc:creator><![CDATA[Toru Kobayashi]]></dc:creator>
            <pubDate>Sun, 13 Feb 2022 16:07:07 GMT</pubDate>
            <atom:updated>2022-02-15T08:33:20.568Z</atom:updated>
            <content:encoded><![CDATA[<p><a href="https://swr.vercel.app/">React Hooks for Data Fetching - SWR</a></p><p>SWR is a React Hooks for data fetching. It manages cached data and revalidates the cache automatically. This is great, but I see developers who are confused by the SWR’s revalidating behaviors. SWR explains the behavior in the documentation though.</p><ul><li><a href="https://swr.vercel.app/docs/revalidation">Automatic Revalidation - SWR</a></li><li><a href="https://swr.vercel.app/docs/options">API Options - SWR</a></li></ul><p>This post explains the behavior. You can see each behavior on the CodeSandbox projects that I’ve created.</p><h3><strong>## Default behavior</strong></h3><p>The default option of SWR ( useSWR(key, fetcher) without options) behaves as the following.</p><ul><li>Revalidate when a page has mounted</li><li>Revalidate when a page gets re-focus</li><li>Revalidate when a page gets back to online</li><li>Revalidate when a request has failed</li></ul><p>Example: <a href="https://codesandbox.io/s/angry-star-ybk38">https://codesandbox.io/s/angry-star-ybk38</a></p><p>I’ve often seen confusion why SWR makes so many requests even if the cache data has been stored. This is because of the behavior. But you can customize the behavior by passing options. So let’s see options to handle the revalidating behaviors.</p><h3>## revalidateOnFocus</h3><p><strong>default: true</strong></p><p>revalidateOnFocus is an option whether SWR revalidates data when a page gets focused or not. This is useful when you want to display the latest data when users get back to a page. But sometimes this leads to unintentional requests. If you want to make requests minimum, you should disable the option.</p><p><a href="https://swr.vercel.app/docs/revalidation#revalidate-on-focus">Automatic Revalidation - SWR</a></p><h3>## revalidateOnReconnect option</h3><p><strong>default: true</strong></p><p>revalidateOnReconnect is a similar option with revalidateOnFocus. But it revalidates data when a page gets back online.</p><p><a href="https://swr.vercel.app/docs/revalidation#revalidate-on-reconnect">Automatic Revalidation - SWR</a></p><h3><strong>## </strong><strong>revalidateIfStale option</strong></h3><p><strong>default: true</strong></p><p>SWR has the revalidateIfStale option and the default value is true. The option indicates whether SWR revalidates data on rendering or not when the cache has stale data. SWR doesn’t revalidate data on rendering when the key has not been changed, so it only affects the behavior on rendering when mounting or the key has been changed. This also doesn’t affect the behaviors of revalidateOnFocus and relivadateOnReconnet.</p><p>Example: <a href="https://codesandbox.io/s/sparkling-paper-gx9n8">https://codesandbox.io/s/sparkling-paper-gx9n8</a></p><h3>## revalidateOnMount option</h3><p><strong>default: undefined</strong></p><p>revalidateOnMount is an option that only affects the behavior on mounting. If revalidateOnMount is true, its fetcher function is always called on mounting even if data is stored in the cache. If revalidateOnMount is false, its fetcher function is never called on mounting. The default value is undefined, not false, which means the default value doesn’t affect its behavior.</p><p>Example: <a href="https://codesandbox.io/s/distracted-pasteur-nko4t">https://codesandbox.io/s/distracted-pasteur-nko4t</a></p><p>⚠️ SWR v1.2.1 doesn’t revalidate data with revalidateOnMount: false even if key has been changed on subsequent updates. I’ve fixed the bug, so it will be fixed in the next release.</p><ul><li><a href="https://github.com/vercel/swr/pull/1837#issuecomment-1030853021">refactor: revalidateIfStale has an effect on updates, not only mounting by koba04 · Pull Request #1837 · vercel/swr</a></li><li><a href="https://github.com/vercel/swr/pull/1847">test: add a test for the behavior of revalidateOnMount when the key has been changed by koba04 · Pull Request #1847 · vercel/swr</a></li></ul><h3>## dedupingInterval</h3><p><strong>default: 2000</strong></p><p>depupingInterval is an interval to dedupe requests with the same key. The default value is 2000, which means that revalidations for the same key don’t happen in 2s. This is useful when you want to avoid making many requests for the same URL in a short period.</p><p>Example: <a href="https://codesandbox.io/s/cool-tdd-fe8ob">https://codesandbox.io/s/cool-tdd-fe8ob</a></p><h3>## useSWRImmutable</h3><p>useSWRImmutable is a React Hooks equivalent with the following option. useSWRImmutable doesn’t revalidate data until calling the mutate function explicitly. This is useful for the data that doesn’t change after loading. I feel that the behavior is what some developers assume as the default behavior of SWR.</p><pre>useSWR(key, fetcher, {<br>  revalidateIfStale: false,<br>  revalidateOnFocus: false,<br>  revalidateOnReconnect: false<br>})</pre><p><a href="https://swr.vercel.app/docs/revalidation#disable-automatic-revalidations">Automatic Revalidation - SWR</a></p><p>You can use useSWRImmutable by importing from swr/immutable.</p><p>Example: <a href="https://codesandbox.io/s/wizardly-khorana-iip2r">https://codesandbox.io/s/wizardly-khorana-iip2r</a></p><p><a href="https://swr.vercel.app/docs/revalidation#disable-automatic-revalidations">Automatic Revalidation - SWR</a></p><h3>## Retry on an error</h3><p>SWR tries to retry a request that is failed by default. You can change the behavior with shouldRetryOnError, errorRetryInterval, and onErrorRetry.</p><p>Note: SWR uses Exponential Backoff Algorithm to prevent making too many requests when an error occurred.</p><p><a href="https://swr.vercel.app/docs/error-handling">Error Handling - SWR</a></p><h3>## Conclusion</h3><p>SWR provides us with various ways to handle revalidating behaviors through options, so you can customize the behaviors with its options. If you want to apply a specific option to all useSWR hooks, you can use SWRConfig as a global configuration.</p><p><a href="https://swr.vercel.app/docs/global-configuration">Global Configuration - SWR</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4d9f08bee813" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Debug values using getters or Proxy]]></title>
            <link>https://koba04.medium.com/how-to-debug-tracked-values-by-getters-or-proxy-76b4608790ad?source=rss-4a249aae4618------2</link>
            <guid isPermaLink="false">https://medium.com/p/76b4608790ad</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[swr]]></category>
            <dc:creator><![CDATA[Toru Kobayashi]]></dc:creator>
            <pubDate>Tue, 07 Dec 2021 14:45:57 GMT</pubDate>
            <atom:updated>2021-12-07T14:57:23.109Z</atom:updated>
            <content:encoded><![CDATA[<p>Getters and Proxy are useful features in JavaScript when you want to track accessing the values. For example, you can only rerender components that used changed values by tracking the usage of values with getters and Proxy.</p><p>SWR adopts the approach to optimize rendering and you can see it in the following document.</p><p><a href="https://swr.vercel.app/docs/advanced/performance#dependency-collection">Performance - SWR</a></p><p>The following is the implementation.</p><pre>return {<br>    mutate: boundMutate,<br>    get data() {<br>      stateDependencies.data = true<br>      return data<br>    },<br>    get error() {<br>      stateDependencies.error = true<br>      return error<br>    },<br>    get isValidating() {<br>      stateDependencies.isValidating = true<br>      return isValidating<br>    }<br>} as SWRResponse&lt;Data, Error&gt;</pre><p><a href="https://github.com/vercel/swr/blob/ba110c317c4888e577d7143c9c8686cfcea6e218/src/use-swr.ts#L501-L512">swr/use-swr.ts at ba110c317c4888e577d7143c9c8686cfcea6e218 · vercel/swr</a></p><p>The returned object is what useSWR returns and stateDependencies is an object to track the usage. The properties of the returned object are implemented as getter functions, so it’s marked as “used” when we access these properties.</p><pre>// the data is marked as &quot;used&quot;<br>const { data } = useSWR(&quot;/api/foo&quot;);</pre><p>This is cool!</p><p>But you should be careful when debugging. If you add console.log to debug the values, you might encounter an unexpected behavior.</p><pre>const { data, error, isValidating } = useSWR(&quot;/api/foo&quot;);<br>console.log({ data, error, isValidating });<br>// Now it renders everytime these values are changed not only data.</pre><p>In the above case, this increases rendering count because this marked all values as “used”.</p><p>SWR uses getter functions, but it can be applied to libraries that use Proxy for the same purpose. So we should be careful about debugging when we deal with libraries that use getter functions or Proxy for optimization.</p><p>I’ve encountered this when I worked on swr-devtools. Currently, this devtool inspects the cache data by defining a getter function to the cache store. But SWR introduced the middleware feature at v1.0.0 so I wanted to try using the middleware to inspect the cache data. But it caused this problem and I had to reconsider the approach.</p><p><a href="https://github.com/koba04/swr-devtools/pull/39">feat: use the middleware instead of injecting a cache by koba04 · Pull Request #39 · koba04/swr-devtools</a></p><p>I’ve also tried to add useDebugValue, which is a built-in hook of React, because it is useful for debugging.</p><p><a href="https://reactjs.org/docs/hooks-reference.html#usedebugvalue">Hooks API Reference - React</a></p><p>But this also caused the same problem and I’ve suspended it.</p><p><a href="https://github.com/koba04/swr-devtools/pull/37">feat: record SWR data with useDebugValue by koba04 · Pull Request #37 · koba04/swr-devtools</a></p><p>I know developing devtools is not common, but “console debug” is a common way to find a problem. If you encountered a problem like “This only happens on debugging”, I recommend you suspect getter functions or Proxy.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=76b4608790ad" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Is storing Non-Serializable Values into a Redux store a bad idea?]]></title>
            <link>https://koba04.medium.com/is-storing-non-serializable-values-into-a-redux-store-a-bad-idea-7dcec532884f?source=rss-4a249aae4618------2</link>
            <guid isPermaLink="false">https://medium.com/p/7dcec532884f</guid>
            <dc:creator><![CDATA[Toru Kobayashi]]></dc:creator>
            <pubDate>Sat, 17 Jul 2021 16:38:32 GMT</pubDate>
            <atom:updated>2021-07-19T14:04:49.303Z</atom:updated>
            <content:encoded><![CDATA[<p>Redux has the following recommendation as <strong>Essentials.</strong></p><blockquote>Do Not Put Non-Serializable Values in State or Actions</blockquote><blockquote>Avoid putting non-serializable values such as Promises, Symbols, Maps/Sets, functions, or class instances into the Redux store state or dispatched actions. This ensures that capabilities such as debugging via the Redux DevTools will work as expected. It also ensures that the UI will update as expected.</blockquote><p><a href="https://redux.js.org/style-guide/style-guide#do-not-put-non-serializable-values-in-state-or-actions">Style Guide | Redux</a></p><p>Yeah, I think it makes sense so that it enables us to store data in a WebStorage or send the store data to a server. Time-travel debugging is also a great feature even though I have never use the feature in production applications 😅</p><p>But, it imposes us on a constraint that we must use data structures that are possible to be serialized as JSON, which means we can only use “String”, “Number”, “Boolean”, “Array”, and “Object”. For me, the constraint makes our implementation difficult and complex.</p><p>I wrote an entry to describe a pattern to use Map/Set for data stored in a Redux store before.</p><p><a href="https://koba04.medium.com/redux-store-patterns-using-es2015-map-f62804755675">Redux Store patterns (using ES2015 Map)</a></p><p>This makes some operations for a list easy because of the APIs that Map/Set has. For example, you can use “Map#get()” and “Map#has()”, instead of “Array#find”, to get an element from a list, which is very straightforward.</p><p>Actually, I don’t like the APIs of Map/Set because those are based on mutability and are lack of APIs. The Iterator Helpers proposal would solve the problem of the lack of APIs, so I’m looking forward to seeing that it reaches stage 4.</p><p><a href="https://github.com/tc39/proposal-iterator-helpers">GitHub - tc39/proposal-iterator-helpers: Methods for working with iterators in ECMAScript</a></p><p>In addition to Map/Set, I’m also looking forward to the proposal of Records/Tuples (Stage2).</p><p><a href="https://github.com/tc39/proposal-record-tuple">GitHub - tc39/proposal-record-tuple: ECMAScript proposal for the Record and Tuple value types. | Stage 2: it will change!</a></p><p>The data structures are based on immutability, so they are very suitable for React applications and Redux applications. Records/Tulples can be serialized with JSON.stringify, but can not be deserialized with JSON.parse even though the proposal has a proposal of JSON.parseImmutable to deserialize Objects and Arrays as Records and Tulples respectively. Does the style guide allows us to use Records/Tulples for data stored in a Redux store? Records/Tulples would become serializable and deseriablizable data structures if an application treats all data as immutable. I think it makes sense to add using Records/Tulples for all data in a Redux application to the style guide because immutability is important to make applications predictable.</p><p>I think the recommendation is a trade-off. As the style guide mentioned, we might have a problem with using non-serializable data structures, but if we can accept the risk, we can get the full power of data structures that JavaScript has. The data store often has complex operations and domain logic, so I think it’s important to pick the most suitable data structure in each case. I’ve seen code that uses Object and Array instead of a proper data structure like Map/Set. However, JavaScript has been evolving, so it’s important to take advantage of the power of evolution.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7dcec532884f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Looking back 2020]]></title>
            <link>https://koba04.medium.com/looking-back-2020-b7b7debaa115?source=rss-4a249aae4618------2</link>
            <guid isPermaLink="false">https://medium.com/p/b7b7debaa115</guid>
            <dc:creator><![CDATA[Toru Kobayashi]]></dc:creator>
            <pubDate>Fri, 01 Jan 2021 14:06:35 GMT</pubDate>
            <atom:updated>2021-01-01T14:06:35.558Z</atom:updated>
            <content:encoded><![CDATA[<p>2020 was the special year for everyone. I have worked from home since February and have changed so many things, which are almost everything. In this year, I didn’t go to meetups and drinks even online. I just worked and spent with my family. Of course It’s not fun, but it’s a good opportunity to start new things. I tried two new things in this year.</p><h3>Studying Computer Science in UoPeople</h3><p>As I mentioned in the post (<a href="https://medium.com/@koba04/studying-at-uopeople-d9abdc9a009f">https://medium.com/@koba04/studying-at-uopeople-d9abdc9a009f</a>), I have been studying Computer Science in UoPeople. This year, I have taken the following courses.</p><ul><li>English Composition 1 (ENGL 0101)</li><li>Online Education Strategies (UNIV 1001)</li><li>Programming Fundamentals (CS 1101)</li><li>Programming 1 (CS 1102)</li><li><strong>[In Progress]</strong> Programming 2 (CS 1103)</li></ul><p>The courses’ contents are not hard for me because I’m already familiar with those topics, but it takes a lot of time because I have to read resources and write many documents in English (about 1000words/week). Especially, peer reviews are time-consuming. My motivation for this is to study Computer Science systematically and not expand my career, which is like a hobby project for me. So I realized that keeping the motivation is hard. I have to use much of my free time for this, which means that I have to give up something like OSS contributions. UoPeople has five terms in a year, and the period of each term is two months and has two weeks of a break between each term, which means that I have to study most of the period.</p><p><a href="https://www.uopeople.edu/become-student/academic-calendar/">https://www.uopeople.edu/become-student/academic-calendar/</a></p><p>I have to spend many times than what I expect before, so I’m considering how to reduce the time for UoPeople without dropping out. But I’m also looking forward to studying further courses because those courses treat more advanced topics than what I have studied.</p><h3>Studying English with a personal trainer</h3><p>I had taken lessons in online English conversations to study English for years. But I doubted that it might not be effective for me. To understand how I should study English, I have used a service to study English with a personal trainer. The period was three months, and I had to study English for two hours every day. I have learned some methods I have never tried before like dictations and shadowing. My English skill didn’t gain so much during the period, but I have learned how to study English, so I think I can improve my English skill in the future, so it was good for me even though the cost was expensive. BTW, it was very hard for me to study English while studying in UoPeople...</p><h3>Lessons Learned</h3><p>Micromanagement is bad. I’m using a task management app, Things, to put anything that I want to do, which includes studying English and reading an article, and so on. I have so many things I want to do, so the list for every day becomes a lot. Each task doesn’t need much time though. I did the tasks every day, but it means that I only did subtle tasks every day. As a result, I didn’t do anything that has a huge impact because I couldn’t spend much time for something that isn’t listed on the task list. For example, I no longer dig into React internals before, and I don’t understand the concept of the latest React internals like Lanes. I guess this could be a bad influence on my career. So I’m considering to reduce the time for my daily tasks.</p><h3>2021</h3><p>I have no specific plan for the year, but I want to focus on a specific thing rather than shallowly working on various things. I want to be a good web developer, so I’ll focus on something related to the web. In addition, I’m still enjoying programming with Rust, so I’d continue to study it.</p><p>Many companies have adopted WFH because of the pandemic. I guess many parts of the companies would resume working in their office after the pandemic like before, but I hope that many companies continue WFH permanently. I think it’s definitely important to meet coworkers in person, but it doesn’t have to do every day; once a month is enough for me. I’m looking forward to being able to work with engineers regardless of the living place.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b7b7debaa115" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[My second term in UoPeople]]></title>
            <link>https://koba04.medium.com/my-second-term-in-uopeople-6d92e408f85c?source=rss-4a249aae4618------2</link>
            <guid isPermaLink="false">https://medium.com/p/6d92e408f85c</guid>
            <category><![CDATA[study]]></category>
            <category><![CDATA[uopeople]]></category>
            <dc:creator><![CDATA[Toru Kobayashi]]></dc:creator>
            <pubDate>Tue, 18 Aug 2020 14:17:36 GMT</pubDate>
            <atom:updated>2020-08-18T14:17:36.928Z</atom:updated>
            <content:encoded><![CDATA[<p>My second term in UoPeople was so hard and frustrating because I’ve taken two courses. In UoPeople, A student is expected to study 15–17 hours per week on each course, so I had to study 30 hours per week for two courses. The courses I’ve taken are basic courses, so I haven’t spent 30 hours per week, but I would have spent 20 hours per week. This amount of study was a burden and frustrating me because I didn’t do anything I want, which is reading books and programming. It also affected our performance of my work.</p><p>The courses I’ve taken were “Online Education Strategies- Univ 1001” and “Programming Fundamentals (Python) — CS 1101”.</p><ul><li><a href="https://www.uopeople.edu/prepare-for-university/online-education-strategies-univ-1001-learning-materials/">https://www.uopeople.edu/prepare-for-university/online-education-strategies-univ-1001-learning-materials/</a></li><li><a href="https://www.uopeople.edu/prepare-for-university/programming-fundamentals-java-cs-1101-learning-materials/">https://www.uopeople.edu/prepare-for-university/programming-fundamentals-java-cs-1101-learning-materials/</a></li></ul><p>Univ1001 was a bit hard because it requires to write many essays and reviews, but some topics like time management and note-taking were helpful for studying in a college. I always fought against minimum word count requirements :)</p><p>CS1101 was easy for me even though I have never used Python for my jobs. It is a fundamental concept of programming, so which programming language is being used was not a concern for me.</p><p>From the next term, I’m going to take only one course each term, which means that it takes eight years to graduate a college. It is definitely long, but it makes sense for me because I have many things I want to do other than graduating a college.</p><p>The course I’m going to take in the next term is an advanced course of CS1101, of which programming language is Java. So I’ll focus on studying English during the term because I believe it is the most effective way for my career. The lesson I’ll take impose on me to studying at least two hours every day, and it might make my next term harder than the second term, but it is exciting for me.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6d92e408f85c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Studying at UoPeople]]></title>
            <link>https://koba04.medium.com/studying-at-uopeople-d9abdc9a009f?source=rss-4a249aae4618------2</link>
            <guid isPermaLink="false">https://medium.com/p/d9abdc9a009f</guid>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Toru Kobayashi]]></dc:creator>
            <pubDate>Sun, 14 Jun 2020 16:23:21 GMT</pubDate>
            <atom:updated>2020-06-14T16:34:31.531Z</atom:updated>
            <content:encoded><![CDATA[<p>I’ve been studying at University of the People(UoPeople) from Japan since April 2020.</p><p><a href="https://www.uopeople.edu/">https://www.uopeople.edu/</a></p><p>I major Computer Science(CS), but before studying CS at UoPeople, I have to pass an English course to prove my English proficiency :) So, I had been studying at the course from April to June.</p><p>I’ve been working as a web developer for about 15 years and am now working as a front-end developer for a company and a front-end advisor for another company. Both jobs are very exciting, and I enjoy my jobs at the companies even though it’s a bit busy.</p><p>In personal, I have two children, so I spend my weekends with my family. So I don’t have enough time to study for a university. However, I decided to study at the university. Why? Here is the story.</p><h3>The Motivation</h3><p>I’ve been studying web application development on my own, which is so much fun, but there are many topics I have to study, and it is very hard to cover all of them. To study fundamental topics for system development, I’ve studied and passed some tests that IPA (Information-technology Promotion Agency) provides. The things I’ve learned through studying for the tests are not connected to my jobs directly, but the knowledge sometimes helps me when I tried to study new topics.</p><p>But the study covered only a few CS topics, so I felt that I want to study more CS topics. But I cannot stop working to study them at a university because I have family and have to provide for them. So I looked for universities to provide a CS course as an online degree to study CS while working for companies as the same as before, and then I found a few universities in Japan. But, I didn’t choose the universities. Why?</p><p>In addition to CS, English is an important topic for me because it is arguably a requirement in software industries. If I want to communicate with developers who maintain OSS libraries or want to send a patch to OSS libraries, I have to communicate with developers in English. To improve my English skills, I try to use English in my life as possible as I can. In the perspective, I think learning CS in English would make sense, so I looked for universities that provide CS as an online degree. As a result, I’ve found UoPeople through watching a TED talk.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2F6kH-uYwt0qs%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D6kH-uYwt0qs&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2F6kH-uYwt0qs%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/40161c43e02f7d4b5fdf165551eaa0a9/href">https://medium.com/media/40161c43e02f7d4b5fdf165551eaa0a9/href</a></iframe><p>This is what I want! UoPeople provides an online course for a CS degree with very cheap cost.</p><p>&gt; a bachelor degree can be completed in 4 years for $4,060</p><p><a href="https://www.uopeople.edu/tuition-free/what-is-tuition-free/">What is Tuition-Free? | University of the People</a></p><p>Getting a CS degree is not a purpose for me, but it will motivate me through the long term for the study. Nowadays, there are many great resources to learn CS for free. For example, CS 253 Web Security is a great class to study how the web works from the perspective of security, and Khan Academy has a CS course to learn algorithms, cryptography, and so on.</p><ul><li><a href="https://web.stanford.edu/class/cs253/">https://web.stanford.edu/class/cs253/</a></li><li><a href="https://www.khanacademy.org/computing/computer-science">https://www.khanacademy.org/computing/computer-science</a></li></ul><p>But I want to learn CS with a curriculum and thought that a university is the best place to achieve it. Anyway, learning computer science is so much fun :) This is my main motivation.</p><h3><strong>The University of the People</strong></h3><p>UoPeople is an online university, so the classes, including exams, are entirely online, which means we can learn anywhere and anytime. To get a grade, we have to study and hand in assignments for about nine weeks. According to their website, we have to study at least15–17 hours per week on each course, which means that if you study only on weekdays, you have to study at least 3 hours every weekday.</p><p>&gt; A student should expect to spend at least 15–17 hours per week on each course. This includes readings, research work, writing, project work, etc.</p><p><a href="https://www.uopeople.edu/faq/how-many-hours-per-week-should-students-expect-to-devote-to-their-coursework/">How many hours per week should students expect to devote to their coursework? | University of the People</a></p><p>In the last term, I took only one course in the term, so I’ll share with you about my experiences in the class, which is ENGL0101.</p><h3>English Course ENGL0101</h3><p>If you have not earned a diploma from an accredited English institution or don’t meet the qualification of some tests like TOEFL, you have to take an English class before studying at UoPeople.</p><p><a href="https://www.uopeople.edu/become-student/admission/for-non-native-english-speakers/">English Proficiency | University of the People</a></p><p>I have a score of TOEIC, but it is not on the list even though Eiken(英検) is included in the list. I considered taking a test of Duolingo because it doesn’t require so much time for a test like TOEFL. But I didn’t take the test and decided to take the English course because I’d like to study English not only CS, so it was a good opportunity for me.</p><p>You can see the curriculum for the class at the following.</p><p><a href="https://www.uopeople.edu/prepare-for-university/english-composition-1-engl-0101-learning-materials/">English Composition 1 - ENGL 0101: Learning Materials | University of the People</a></p><p>I cannot share the details of the class. In this class, I’ve read stories, reviewed them, discussed with classmates, assessed peer’s assignment, and taken a self-quiz each week. Especially, I was struggled to read literature because what I read regularly is about technology, which many of my vocabularies are from the technology area. Moreover, literature is usually vaguer than articles about technologies, so I had to take much time to understand the story of literature.</p><p>Through this class, I realized that my vocabularies are less than other classmates, so I feel that I have to read books from various categories written in English.</p><p>But the hardest part of taking the class is to keep studying for nine weeks. I planed to study at weekends (Fri 〜 Sun) because I might not be able to use weekdays for the study. So I studied for about five hours at weekends during the term. But it was very tough because I have to play with children at weekends. So my study time was after having been playing with them. In addition to that, keeping studying nine weeks was very difficult because it is a very long term and some weekends had no time for the study because I was very busy, or tired. Actually, the last few weeks of the term were very hard to keep my motivation.</p><p><strong>Final Exam with Proctor</strong></p><p>The class has a final exam that requires a proctor. We can choose an online proctor or offline proctor. I don’t have any people who can be the proctor, so I chose an online proctor. We can get a proctor at the service, ProctorU.<br>- <a href="https://www.proctoru.com/">https://www.proctoru.com/</a></p><p>Of course, this was the first time I do a test online with a proctor, which was a very strange experience. To take the final exam, we must secure a room that anyone cannot enter and has a clean desk. Before taking the test, I connected to a proctor and had to prove that my environment fulfills the test’s requirement. To do it, I had to follow the proctor’s instructions, which are hiding an external display, putting away my mobile phone, and showing my entire room to the proctor using a web camera on my laptop.</p><p>Of course, these instructions were in English, so I had to communicate with the proctor in English. Speaking in English is not necessary at UoPeople because most of the activities are reading and writing. But a final exam with a proctor is a rare case that we have to speak and listen in English.</p><p>Next, I had to allow the proctor to operate on my laptop. After I allowed this, the proctor closed applications and browser tabs that not required for the exam, which was a weird experience that my laptop is controlled remotely.</p><p>After I finished the ready to take exam, I can start the exam. I took the test on an external site, which seemed to be a system of Oxford. The system was very poor. For example, it seemed not to allow us to go back to previous questions to answer them again. I didn’t know the system, so I wasted about 30 minutes because I cannot back to previous questions. I usually finish answering all questions as soon as possible and then re-answer questions carefully…</p><p>The worst experience was at the time I’ve just finished the exam. I followed the instruction on the page and clicked the “close the window” button, but after that, the page suddenly showed a login page without any feedbacks for the final exam; there is no message to tell whether the submission was successful or not. So I asked the proctor, and the proctor said that you had finished the exam. It almost took a week to be able to see the result of the final exam, so I spent days while worrying about that.<br>Fortunately, I have succeeded in submitting the final exam and passed the course!</p><p>But according to the UoPeople staff, it is only for the final exam for English class, the other tests are taken on the UoPeople website, which is called Moodle. So be careful when you take the final exam for the English course.</p><h3><strong>The Next</strong></h3><p>This is just a start-line of studying CS, and the next term is starting the next weekend; I will take two courses, which are a CS course and a general course, so I would have to study much more than the previous term, but I’m very excited!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d9abdc9a009f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Validate to work  your application on IE11 using webpack plugin]]></title>
            <link>https://koba04.medium.com/validate-to-work-your-application-on-ie11-using-webpack-plugin-b581427ee3e?source=rss-4a249aae4618------2</link>
            <guid isPermaLink="false">https://medium.com/p/b581427ee3e</guid>
            <category><![CDATA[webpack]]></category>
            <dc:creator><![CDATA[Toru Kobayashi]]></dc:creator>
            <pubDate>Mon, 18 May 2020 15:53:14 GMT</pubDate>
            <atom:updated>2020-05-18T15:53:14.249Z</atom:updated>
            <content:encoded><![CDATA[<h3>Building a webpack plugin to validate your bundle files for IE11</h3><p>I guess most developers don’t use IE11 as their developer environment. But we often have to support IE11 as an environment for our applications. These days, we write application code using TypeScript, ES2020, or JSX and compile them to ES5 JavaScript, so we don’t have to care about what ECMAScript features our support browsers support, because these are responsibilities of compilers like TypeScript and Babel.</p><p>But I still see that our application displays a blank page only on IE11. Why? The reason is that we don’t usually compile source code in node_modules. We merely bundle the source code. It means that your application doesn’t work on IE11 if any dependencies published their code written as &gt;ES2015.</p><p>Fortunately, many npm packages publish code compiled to ES5. But there is no rule to have to compile to ES5 to publish an npm package. Node already supports &gt;ES2015 features, so it doesn’t make sense to compile to ES5 if a package author intended to use the package in Node.js. Even a package for browsers, it might make sense to compile to ES2015, not ES5, because browsers except IE11 already support ES2015 features. In addition to that, it is tough to confirm what ES version each dependency package is using. To confirm this, we have to understand the compiler settings of the package.</p><p>In addition to that, it’s tough to build code for various targets properly. For example, `polished` accidentally published a version that includes code compiled to ES2015 and pointed it out at the `module` field in `package.json.` Fortunately, they have fixed quickly, but it seems to be a bit hard to find it.</p><p><a href="https://github.com/styled-components/polished/issues/504">https://github.com/styled-components/polished/issues/504</a></p><p>Of course, we could avoid this by compiling source code in `node_modules,` but it takes extra time. IIRC, there was a case to break code by compiling code that has already compiled, which is a double compiling. I have to dig into the case, but this time, I’ve taken another option.</p><p>To detect to include not ES5 compatible code in our builds, I’ve created `<strong>ecma-version-validator-webpack-plugin</strong>,` which is a webpack plugin to validate that build files are compatible with specific ES version or not. This plugin makes it possible to avoid shipping source code that is not ES5 compatible.</p><p><a href="https://github.com/koba04/ecma-version-validator-webpack-plugin">https://github.com/koba04/ecma-version-validator-webpack-plugin</a></p><pre>const { ECMAVersionValidatorPlugin } = require(&quot;ecma-version-validator-webpack-plugin&quot;);<br><br>module.exports = {<br>    // ...<br>    plugins: [<br>      new ECMAVersionValidatorPlugin(/* options */)<br>    ],<br>}</pre><p>This plugin emits an error if the out file includes &gt;=ES2015 syntax in the file. You can change the target ECMAScript version by `ecmaVersion` option.<br>This plugin can only detect syntax errors, cannot detect the usage of built-in objects and methods newly added, so it cannot avoid runtime errors entirely, but it’s still useful. I recommend running a test using this plugin on CI like the following.</p><figure><img alt="A result of a failing test on CI" src="https://cdn-images-1.medium.com/max/583/1*-4MEDJxyhFNatwysM5D4Xg.png" /></figure><ul><li><a href="https://circleci.com/gh/kufu/smarthr-ui/5960">https://circleci.com/gh/kufu/smarthr-ui/5960</a></li><li><a href="https://github.com/kufu/smarthr-ui/pull/779">https://github.com/kufu/smarthr-ui/pull/779</a></li></ul><p>The followings are tips to write a webpack plugin.</p><p><strong>How to write a webpack plugin</strong></p><p>webpack provides many hooks for plugins.</p><p><a href="https://webpack.js.org/api/compiler-hooks/">https://webpack.js.org/api/compiler-hooks/</a></p><p>`ecma-version-validator-webpack-plugin` have to take emitted files, so this plugin uses `emit` hook to validate build contents. This implementation is very simple, which validates assets and push errors if an error occurred.</p><pre>apply(compiler: Compiler) {                             <br>  compiler.hooks.emit.tap(this.name, (compilation) =&gt; {<br>    try {<br>      validate(compilation.assets, {<br>        ecmaVersion: this.ecmaVersion,<br>        test: this.test,<br>      });<br>    } catch (e) {<br>      compilation.errors.push(e);<br>    }<br>  });<br>}</pre><p><a href="https://github.com/koba04/ecma-version-validator-webpack-plugin/blob/master/src/index.ts">koba04/ecma-version-validator-webpack-plugin</a></p><p>See more details to see how to create a webpack plugin.</p><p><a href="https://webpack.js.org/contribute/writing-a-plugin/">https://webpack.js.org/contribute/writing-a-plugin/</a></p><h3><strong>How to test a webpack plugin</strong></h3><p>This plugin has some tests. Most of the tests are separated from `webpack` so we can write tests as regular unit testing. To write unit testing using a webpack compiler is also straightforward. See the example in the following.</p><p>First, I’ve created a webpack compiler using Node.js API of webpack.</p><p>Second, I’ve used `memfs` as the outputFileSystem because I don’t want to output an actual bundle file by this test; memfs is a simple in-memory filesystem.</p><pre>import path from &quot;path&quot;;<br>import webpack from &quot;webpack&quot;;<br>import { fs } from &quot;memfs&quot;;</pre><pre>// This will be able to remove at webpack v5<br>// @ts-ignore https://github.com/webpack/webpack/pull/9251<br>fs.join = path.join;</pre><pre>it(&quot;should emit an error if an input file is not valid&quot;, (done) =&gt; {<br>  const compiler = webpack({<br>    mode: &quot;development&quot;,<br>    entry: path.resolve(__dirname, &quot;fixtures&quot;, &quot;es2015.js&quot;),<br>    devtool: &quot;nosources-source-map&quot;,<br>    plugins: [new ECMAVersionValidatorPlugin()],<br>  });<br>  // @ts-ignore https://github.com/webpack/webpack/pull/9251<br>  compiler.outputFileSystem = fs;<br>  compiler.run((err, stats) =&gt; {<br>    expect(err).toBeNull();<br>    expect(stats.compilation.errors.length).toBe(1);<br>    done();<br>  });<br>});</pre><p><a href="https://github.com/koba04/ecma-version-validator-webpack-plugin/blob/master/src/__tests__/index.test.ts#L33-L62">koba04/ecma-version-validator-webpack-plugin</a></p><p>The interface of outputFileSystem of webpack v4 expects to have a join() method, which is not implemented on `memfs`. So we have to add path.join() method into an instance of `memfs`. This is fixed at webpack v5.</p><p>Note: I have an issue `memfs` throws an unexpected error. I don’t dig into the issue yet, so I’ll work on it later.</p><p><a href="https://github.com/kufu/smarthr-ui/pull/779#discussion_r425298223">https://github.com/kufu/smarthr-ui/pull/779#discussion_r425298223</a></p><h3>Acknowledgement</h3><p>After I’ve published the webpack plugin, <a href="https://github.com/gfx">gfx</a> taught me that he also built a webpack that is the same purpose before😇.</p><p><a href="https://github.com/bitjourney/check-es-version-webpack-plugin">https://github.com/bitjourney/check-es-version-webpack-plugin</a></p><p>I’ve learned the way to write unit tests with webpack compiler by the repository. Thank you!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b581427ee3e" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>