<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Yanze Dai</title>
    <description>The latest articles on DEV Community by Yanze Dai (@daiyanze).</description>
    <link>https://dev.to/daiyanze</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F433773%2F73ea9000-6e72-4658-9b2c-e72b2fd08541.jpeg</url>
      <title>DEV Community: Yanze Dai</title>
      <link>https://dev.to/daiyanze</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/daiyanze"/>
    <language>en</language>
    <item>
      <title>An indepth explanation of the Knuth-Morris-Pratt algorithm</title>
      <dc:creator>Yanze Dai</dc:creator>
      <pubDate>Thu, 30 Jun 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/pitayan/an-indepth-explanation-of-the-knuth-morris-pratt-algorithm-2ife</link>
      <guid>https://dev.to/pitayan/an-indepth-explanation-of-the-knuth-morris-pratt-algorithm-2ife</guid>
      <description>&lt;p&gt;Originally published on &lt;a href="https://pitayan.com/posts/kmp-algorithm-indepth/"&gt;Pitayan | An indepth explanation of the Knuth-Morris-Prat&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;String matching is a very fundamental task for computer. We’ve seen many programs that allow you to pop out the search box via Ctrl + F / Cmd + F.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6Fb2bmiy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/posts/kmp-algorithm-indepth/images/control_f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6Fb2bmiy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/posts/kmp-algorithm-indepth/images/control_f.png" alt="Safari control+f search bar" width="698" height="58"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For example, we could check if there’s a string of “search” from “I’m searching on Google”. There’re many algorithms that could help you achieve this function. Knuth-Morris-Pratt (as known as “KMP”) is one of them (See also Rabin-Karp, Boyer-Moore).&lt;/p&gt;

&lt;p&gt;This algorithm is named after the 3 inventors. I bet you’ve heard of this book &lt;a href="https://www.google.com/url?sa=t&amp;amp;rct=j&amp;amp;q=&amp;amp;esrc=s&amp;amp;source=web&amp;amp;cd=&amp;amp;ved=2ahUKEwierP6Fqbz4AhVDMXAKHc6vBFoQFnoECAsQAQ&amp;amp;url=https://en.wikipedia.org/wiki/The_Art_of_Computer_Programming&amp;amp;usg=AOvVaw0ZT6UiIjWJEf_Zv9NHZ_jp"&gt;The art of computer programming&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kdfMYM8F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/posts/kmp-algorithm-indepth/images/the_art_of_computer_programming.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kdfMYM8F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/posts/kmp-algorithm-indepth/images/the_art_of_computer_programming.jpg" alt="The art of computer programming" width="880" height="726"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The author of this book &lt;a href="https://en.wikipedia.org/wiki/Donald_Knuth"&gt;Donald Knuth&lt;/a&gt; (The famous comupter scientist) is one of the inventors of this algorithm. (I haven’t read his book yet but let me pay my best tribute to this great scientist)&lt;/p&gt;

&lt;p&gt;This algorithm was so difficult to me to understand until I found these 2 following articles from Google search.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.w3spot.com/2020/07/kmp-algorithm-explained-in-plain-english.html"&gt;https://www.w3spot.com/2020/07/kmp-algorithm-explained-in-plain-english.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.baeldung.com/cs/knuth-morris-pratt"&gt;https://www.baeldung.com/cs/knuth-morris-pratt&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now I wanna try to explain this amazing algorithm in my own language coz any day in the future I might need to go over this amazing creation.&lt;/p&gt;

&lt;h2&gt;
  
  
  #The bruteforce issue
&lt;/h2&gt;

&lt;p&gt;Suppose we have a string of&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“ABCD EFGHABCAGBC” (haystack)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and a match string of&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“BCAGBC” (needle)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We might have a bruteforce solution by comparing each of the characters in both haystack and needle as below.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First character not match, move to next position&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;ABCD EFGHABCAGBC&lt;/p&gt;

&lt;p&gt;^&lt;/p&gt;

&lt;p&gt;BCAGBC&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;First character “B” matched&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;ABCD EFGHABCAGBC&lt;/p&gt;

&lt;p&gt;..^&lt;/p&gt;

&lt;p&gt;..BCAGBC&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Second character “C” matched&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;ABCD EFGHABCAGBC&lt;/p&gt;

&lt;p&gt;…..^&lt;/p&gt;

&lt;p&gt;..BCAGBC&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Thrid character not match, move pointer to next needle character&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;ABCD EFGHABCAGBC&lt;/p&gt;

&lt;p&gt;…….^&lt;/p&gt;

&lt;p&gt;..BCAGBC&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;First character not matched, move needle head to next haystack character&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;ABCD EFGHABCAGBC&lt;/p&gt;

&lt;p&gt;…..^&lt;/p&gt;

&lt;p&gt;…..BCAGBC&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then it goes on with the previous steps… Just take a look at the GIF below, this will make you further understand it intuitively.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TjxWIUc3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://pitayan.com/posts/kmp-algorithm-indepth/images/bruteforce_solution.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TjxWIUc3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://pitayan.com/posts/kmp-algorithm-indepth/images/bruteforce_solution.gif" alt="The bruteforce solution animation" width="250" height="122"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you see the problem, right? It’s not efficient because we’re trying to move the search position to the already compared position.&lt;/p&gt;

&lt;p&gt;When we compared “D” with “A” at step 4, we already know that the current haystack characters are “BCD” and even we move to the next haystack postion character “C” it will obviously fail the attempt.&lt;/p&gt;

&lt;p&gt;Thus, we need a good strategy to save us from comparing characters from the already “checked” positions.&lt;/p&gt;

&lt;h2&gt;
  
  
  #How does the KMP magic take effect?
&lt;/h2&gt;

&lt;p&gt;Actually KMP does nothing special, apart of checking the next character it’ll just do the following.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Reuse the known information&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;How?&lt;/p&gt;

&lt;p&gt;Let’s flashback to step 4 when it tries to compare “D” with “C”. Instead of aligning the head character of “BCC” with next haystack character “C”, KMP will skip comparing the character “C” and move it to a later position.&lt;/p&gt;

&lt;p&gt;To achieve this, KMP also has to generate a “Partial Match Table” according to the needle string. In our case, the table may look like this.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;B&lt;/th&gt;
&lt;th&gt;C&lt;/th&gt;
&lt;th&gt;A&lt;/th&gt;
&lt;th&gt;G&lt;/th&gt;
&lt;th&gt;B&lt;/th&gt;
&lt;th&gt;C&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;-1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;(Note: Usually we set the first value of the “Partial Match Table” to -1 for programming convenience)&lt;/p&gt;

&lt;p&gt;To know how this table is generated, we need to understand the following terms first&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;prefix collection&lt;/strong&gt; : All combinations of the needle string excluding the last character&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;suffix collection&lt;/strong&gt; : All conbimations of the needle string exlucding the first character&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;partial match value&lt;/strong&gt; : The longest element length of the union of prefix collection and suffix collection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, we’ll evaluate each “partial match string’s” value&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;“B”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;“BC”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;“BCA”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;“BCAG”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;“BCAGB”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;“BCAGBC”&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Okay, let’s continue the case in this article, step 4 -&amp;gt; matching “D” and “A”.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ABCD EFGHABCAGBC&lt;/p&gt;

&lt;p&gt;…….^&lt;/p&gt;

&lt;p&gt;..BCAGBC&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Well, the result is false, we will need to move the needle’s position by 2. You will be needing the following formula to calculate the “positions to move”&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;positions to move = matched count - partial match value&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this case, we’ve already matched 2 characters “B” and “C”. The “partial match value” under character “A” is 0. Thus, we have to move 2 characters which aligned “D” and “B” in the same comparing position.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ABCD EFGHABCAGBC&lt;/p&gt;

&lt;p&gt;…….^&lt;/p&gt;

&lt;p&gt;…….BCAGBC&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(Skip the ones in the middle “EFGHA”) We found the head character match, there’ll be another around of comparison until the end.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ABCD EFGHABCAGBC&lt;/p&gt;

&lt;p&gt;…………………..^……….^&lt;/p&gt;

&lt;p&gt;…………………..BCAGBC&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here is the intuitive GIF to help you understand if better.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MJRdTIAi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://pitayan.com/posts/kmp-algorithm-indepth/images/kmp_solution.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MJRdTIAi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://pitayan.com/posts/kmp-algorithm-indepth/images/kmp_solution.gif" alt="The KMP solution animation" width="250" height="122"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #Actual code (Bruteforce)
&lt;/h2&gt;

&lt;p&gt;Before we dive into the KMP solution, let’s take a look at how we usually implement it “bruteforcely”.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;int bruteforce(char *haystack, char *needle)
{
    int i = 0,
        j = 0;
    int h_len = strlen(haystack);
    int n_len = strlen(needle);

    // When needle is an empty string, always return 0.
    if (n_len == 0) return 0;

    // Until i,j reaches the end of each string
    while (h_len &amp;gt; i &amp;amp;&amp;amp; n_len &amp;gt; j)
    {
        // Aggregate i,j when there's a match
        if (haystack[i] == needle[j])
        {
            i++;
            j++;
        }
        else
        {
            // NOTE: This never efficient
            // Jump to the next character of which doesn't match
            i = i - j +1;
            // Jump to needle head
            j = 0;
        }
    }

    // Once the while loop finishes, j should equal to needle length if there's any match
    if (j == n_len) {
        return i - j;
    }

    return -1;
}

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  #Actual code (KMP)
&lt;/h2&gt;

&lt;p&gt;The coding will be separated into 2 parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;next array (partial match table)&lt;/li&gt;
&lt;li&gt;main iteration&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  #1. Next array
&lt;/h3&gt;

&lt;p&gt;Next array may appear very different to the explanation of the “prefix and suffix” thing. But indeed, the implementation used some tricks to make the time complexity stay as linear. In a simple word:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To match the needle string using itself&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Note: Make sure to debug it so that you could fully understand how this amazing code works.&lt;/p&gt;

&lt;p&gt;Alternatively, the blow GIF will help you out if you’re lazy for debugging.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xGqNbo2l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://pitayan.com/posts/kmp-algorithm-indepth/images/next_array.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xGqNbo2l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://pitayan.com/posts/kmp-algorithm-indepth/images/next_array.gif" alt="KMP Next Array" width="482" height="302"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;int *get_next(char *needle, int len)
{
    int i = 0,
        j = -1;
    // Allocate a space of heap memory to store the "partial match table"
    int *next = (int *)calloc(len, sizeof(int));

    // Make the first element -1 for convenience
    next[0] = -1;

    // Until j reaches the end of needle
    while (len &amp;gt; j) {
        if (j == -1 || needle[i] == needle[j])
        {
            ++i;
            ++j;
            // j works as an accumulator. It gives you the number of how many
            // characters has matched
            next[i] = j;
        }
        else
        {
            j = next[j];
        }
    }

    // Caller will free the heap memory
    return next;
}

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  #2. Main iteration
&lt;/h3&gt;

&lt;p&gt;The main part of KMP is almost the same to building the “next array”. As the whole algorithm is actually a format of &lt;a href="https://en.wikipedia.org/wiki/Finite-state_machine"&gt;“finite-state machine”&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;int kmp(char *haystack, char *needle)
{
    int i = 0,
        j = 0;
    int h_len = strlen(haystack);
    int n_len = strlen(needle);

    // When needle is an empty string, always return 0.
    if (n_len == 0) return 0;

    // get "Partial Match Table" as next
    int *next = get_next(needle, n_len);

    // Until i,j reaches the end of each string
    while (h_len &amp;gt; i &amp;amp;&amp;amp; n_len &amp;gt; j)
    {
        // Aggregate i,j only when
        // 1. j == needle[0] == -1, this means there's no succesful match, need to restart at a new position
        // 2. Same character appeared in both haystack and needle
        if (j == -1 || haystack[i] == needle[j])
        {
            i++;
            j++;
        }
        else
        {
            // Assign the "Partial Match Table" value
            j = next[j];
        }
    }

    // (Don't forget to free the heap memory)
    free(next);

    // Once the while loop finishes, j should equal to needle length if there's any match
    if (j == n_len) {
        return i - j;
    }

    return -1;
}

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  #In the end
&lt;/h2&gt;

&lt;p&gt;Honestly, the KMP algorithm is still very much confusing to me especially the reason why they implemented that way. But it truly proves an excellent methodology of solving a “patternish” problem. The KMP algorithm is not the most efficient algorithm compared to “Boyer Moore” and “Rabin-Karp”. Most of our editors “find” function adopts “Boyer Moore” algorithm. I’ll write another article to explain it.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Capture the flag: A Node.js web app vulnerability practice (part 1)</title>
      <dc:creator>Yanze Dai</dc:creator>
      <pubDate>Fri, 20 May 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/pitayan/capture-the-flag-a-nodejs-web-app-vulnerability-practice-part-1-1iii</link>
      <guid>https://dev.to/pitayan/capture-the-flag-a-nodejs-web-app-vulnerability-practice-part-1-1iii</guid>
      <description>&lt;p&gt;Originally published on &lt;a href="https://pitayan.com/posts/capture-web-app-vulnerabilities"&gt;Pitayan | Capture the flag: A Node.js web app vulnerability practice (part 1)&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Last time our team had a small JavaScript workshop together (Check this article here: &lt;a href="https://dev.to/pitayan/what-do-these-consolelog-print-out-52i5"&gt;8 Javascript quiz that may confuse you&lt;/a&gt;). And we’ve done it quite well. Everyone enjoyed solving those small problems.&lt;/p&gt;

&lt;p&gt;Well, this time, my teammate has brought us a practice of finding the Node.js web application vulnerabilities.&lt;/p&gt;

&lt;p&gt;It’s not a hard one. There’re &lt;strong&gt;2&lt;/strong&gt; vulnerabilities in the web app. The way to “capture the flag” is to succeed in login. If you made it, text of &lt;code&gt;flag&lt;/code&gt; will be displayed in the page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Q81JhVoj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://pitayan.com/ea45a374e8ce22cb999ff0df5cd24344/login.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Q81JhVoj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://pitayan.com/ea45a374e8ce22cb999ff0df5cd24344/login.gif" alt="A successful login process" width="880" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #Get Started
&lt;/h2&gt;

&lt;p&gt;Follow the instructions and make sure that you’ve already got everything on track. Now, you’re only allowed to look at the repository files of&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;README.md&lt;/li&gt;
&lt;li&gt;vuln1/index.js&lt;/li&gt;
&lt;li&gt;uploads/*&lt;/li&gt;
&lt;li&gt;package*.json&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remember not to cheat before you complete the quiz (The God is watching you). Here are some notices before starting it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Please don’t open &lt;code&gt;.env&lt;/code&gt; file.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Please complete the quiz without changing the source code (However, debugging is allowed).&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Please follow the above advices&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  #0. Prerequisites
&lt;/h3&gt;

&lt;p&gt;Make sure that you have Node 16+ install on your system (NPM v8 is required). A recommended way to install Node.js via &lt;a href="https://github.com/nvm-sh/nvm"&gt;nvm&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ nvm install 16
...
$ nvm use 16
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #1. Clone the repo
&lt;/h3&gt;

&lt;p&gt;Here is the repository link: &lt;a href="https://github.com/daiyanze/vulnerability-code-challenge"&gt;https://github.com/daiyanze/vulnerability-code-challenge&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git clone git@github.com:daiyanze/vulnerability-code-challenge.git
$ cd crack-the-code-challenge &amp;amp; npm i
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #2. Start the server
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm -w challenges/vuln1 run start

&amp;gt; vuln1@1.0.0 start
&amp;gt; node index.js

Started on http://localhost:81
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #3. Open &lt;a href="http://localhost:81"&gt;http://localhost:81&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Then the following screen will pop out.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9qkKdFcy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/5dadc2c6e85b838efc29cc378fd307d3/88aa2/admin_panel.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9qkKdFcy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/5dadc2c6e85b838efc29cc378fd307d3/88aa2/admin_panel.png" alt="Your everything about cracking the code starts from here" title="Your everything about cracking the code starts from here" width="880" height="595"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Your everything about cracking the code starts from here&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This admin page does 4 things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Modify the JSON file’s name &amp;amp; content&lt;/li&gt;
&lt;li&gt;Upload your JSON file&lt;/li&gt;
&lt;li&gt;Print out the JSON file content&lt;/li&gt;
&lt;li&gt;Login&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Your mission now is to pass the login step, and let the page display &lt;code&gt;flag&lt;/code&gt; text.&lt;/p&gt;
&lt;h2&gt;
  
  
  #Hints
&lt;/h2&gt;

&lt;p&gt;If you are still not sure how to do it, pry out the hints below 1 by 1. But please do remember to read the code in &lt;code&gt;index.js&lt;/code&gt; file first. You’ll find many useful clues in it.&lt;/p&gt;
&lt;h1&gt;
  
  
  Hint 1
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;What about browsing other files on the server?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;
  
  
  Hint 2
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;Take a good look at the messages from your terminal.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;
  
  
  Hint 3
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;How about changing the content of the &lt;code&gt;parsed.json&lt;/code&gt; file?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;
  
  
  Hint 4
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;You know you could mutate &lt;code&gt;prototypes&lt;/code&gt; and &lt;code&gt;__proto__&lt;/code&gt;, don’t you?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;
  
  
  Hint 5
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;Just go to answer section. It’ll tell you how.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  #When flag is captured
&lt;/h2&gt;

&lt;p&gt;Don’t read this section if you haven’t captured the flag. But I really hope you’ve already made it. Otherwise the following will just lead you to a detailed explanation before you could actually resolve the mystery by yourself.&lt;/p&gt;
&lt;h3&gt;
  
  
  #Explanation
&lt;/h3&gt;

&lt;p&gt;In the first few paragraphs of this article, it’s mentioning that we have 2 vulnerabilities. And they are both threatening the login step.&lt;/p&gt;

&lt;p&gt;The key points are&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Where do we get the password?&lt;/p&gt;

&lt;p&gt;How do we cheat the authentication?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once we have a clue of how to handle these things above, then the answer would be right above the surface.&lt;/p&gt;

&lt;p&gt;It’s not very hard to associate the password with the mysterious &lt;code&gt;.env&lt;/code&gt; file right? Since you’ve been told not to look at it, then curiosity may have driven you toward the “method” of opening that file as what’s written in the “Hint 1”.&lt;/p&gt;

&lt;p&gt;So if you try to open the content of &lt;code&gt;.env&lt;/code&gt; file via “Read uploaded JSON”, the password will appear. Oh, we got a password now. Then that should work? Certainly nope. It’s just a start.&lt;/p&gt;

&lt;p&gt;Remember what’s written in the source code about authentication?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const user = {
  // just pretend this comes from a db
  password: "$2a$12$3cSdZFdEIG9FizllB9.5E.M8DTQQ185zyITtBTBz7Lz3Va8s0xjSy",
};

switch (user.auth_method ?? "bcrypt") {
  case "bcrypt":
    passed = bcrypt.compareSync(req.body.password, user.password);
    break;
  case "superadmin":
    passed = req.body.password === process.env.SUPER_ADMIN_PASS;
    break;
  default:
    throw new Error("invaid auth method");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The encrypted &lt;code&gt;password&lt;/code&gt; is already there but you can’t decrypt it easily. So the breakthrough point is &lt;code&gt;user.auth_method&lt;/code&gt;. You need to find a way to turn &lt;code&gt;user.auth_method&lt;/code&gt; value into &lt;code&gt;"superadmin"&lt;/code&gt;. But how?&lt;/p&gt;

&lt;p&gt;Well, here’s one useful information from the terminal when you install the package. There’s one critical severity vulnerability in your package.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;added 110 packages, and audited 111 packages in 8s

5 packages are looking for funding
  run `npm fund` for details

1 critical severity vulnerability

To address all issues, run:
  npm audit fix

Run `npm audit` for details.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you tried to &lt;code&gt;npm audit fix&lt;/code&gt;, the solution would come to your mind easily if you had experience with “prototype pollution”.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;added 1 package, removed 1 package, and audited 120 packages in 2s

10 packages are looking for funding
  run `npm fund` for details

# npm audit report

lodash &amp;lt;=4.17.20
Severity: critical
Prototype Pollution in lodash - https://github.com/advisories/GHSA-jf85-cpcp-j695
Prototype Pollution in lodash - https://github.com/advisories/GHSA-fvqr-27wr-82fm
Command Injection in lodash - https://github.com/advisories/GHSA-35jh-r3h4-6jhm
Regular Expression Denial of Service (ReDoS) in lodash - https://github.com/advisories/GHSA-x5rq-j2xg-h7qm
Prototype Pollution in lodash - https://github.com/advisories/GHSA-p6mc-m468-83gw
fix available via `npm audit fix --force`
Will install lodash@4.17.21, which is outside the stated dependency range
node_modules/lodash

1 critical severity vulnerability

To address all issues, run:
  npm audit fix --force
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is a very good article about “prototype pollution”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://brightsec.com/blog/prototype-pollution/"&gt;https://brightsec.com/blog/prototype-pollution/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In a simple word, “Prototype pollution” is “to extend / modify the global objects”.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Object. __proto__.auth_method = "superadmin"
Object.constructor.prototype.auth_method = "superadmin"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the above trick, you could just add some extra seasonings to that JSON content. Now you are good to capture the flag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{" __proto__":{"auth_method":"superadmin"}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The vulnerability that helps you “overcome” the password authentication comes from &lt;code&gt;lodash &amp;lt;= 4.17.20&lt;/code&gt;. Refer to this &lt;a href="https://github.com/advisories/GHSA-jf85-cpcp-j695"&gt;page&lt;/a&gt; to get more details.&lt;/p&gt;

&lt;h3&gt;
  
  
  #Answer
&lt;/h3&gt;

&lt;p&gt;The solution takes only 3 steps.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Input the following to “Secure JSON formatter” &lt;code&gt;&amp;lt;textarea&amp;gt;&lt;/code&gt; and click “Format &amp;amp; Upload” button.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{" __proto__":{"auth_method":"superadmin"}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Input &lt;code&gt;../.env&lt;/code&gt; to “Read uploaded JSON” and click “Read” button&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Input what you get from step 2 to “Login” password&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then you’ll get a &lt;code&gt;flag&lt;/code&gt; text in the page.&lt;/p&gt;

&lt;h2&gt;
  
  
  #Summary
&lt;/h2&gt;

&lt;p&gt;This practice itself isn’t a very hard one. But at least I think gave us some good warnings of taking care of our project’s securities.&lt;/p&gt;

&lt;p&gt;The first important thing in making secure applications is to carry out “user-input validation &amp;amp; sanitization” all the time and never use those inputs directly.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When shall we trust the end users? When there’s no input at all.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The second important thing is from our projects. Some of the developers don’t usually pay attention to the information from the &lt;code&gt;npm audit&lt;/code&gt;. There’re so many reasons of “we don’t have to” (you know why :p). But when it comes to some security concerns, &lt;code&gt;npm audit&lt;/code&gt; has already given us enough clues to follow up with. Thus, constantly check and update our dependencies will probably do us a favor in building a rather secured application.&lt;/p&gt;

</description>
      <category>vulnerabilities</category>
      <category>workshop</category>
    </item>
    <item>
      <title>Interview Officer: "Tell me about Cookies Session and Tokens". Me: "Emm..."</title>
      <dc:creator>Yanze Dai</dc:creator>
      <pubDate>Thu, 12 May 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/pitayan/interview-officer-tell-me-about-cookies-session-and-tokens-me-emm-221p</link>
      <guid>https://dev.to/pitayan/interview-officer-tell-me-about-cookies-session-and-tokens-me-emm-221p</guid>
      <description>&lt;p&gt;Originally published on &lt;a href="https://pitayan.com/posts/sessions-cookies-and-tokens"&gt;Pitayan | Interview Officer: "Tell me about Cookies Session and Tokens". Me: "Emm..."&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;In late 2021, I took an interview with a hotshot IT company for a front end engineer position. During the interview process, the interview officer’s question of “Tell me about cookie session and token” got me into my knowledge blind spot.&lt;/p&gt;

&lt;p&gt;I will be explaining some details around “cookies” “sessions” and “tokens”.&lt;br&gt;&lt;br&gt;
Meanwhile, hope this article will remind everyone to strengthen related knowledge points so that it could come to help any day in the future when necessary.&lt;/p&gt;
&lt;h2&gt;
  
  
  #The interview briefing
&lt;/h2&gt;

&lt;p&gt;It was an online interview with only interview officer and me in that meeting. The officer was a bit late but he was still very nice and polite. He introduced himself and the interview flow.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Self introduction&lt;/li&gt;
&lt;li&gt;Recent projects&lt;/li&gt;
&lt;li&gt;Fundamental knowledge quiz&lt;/li&gt;
&lt;li&gt;Algorithm quiz&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There’re quite few casual talks among the interview and the whole process took about 50 min (should be 1 hour but he was late, so 10 min was gone…). I did my best to answer each questions as I could.&lt;/p&gt;

&lt;p&gt;However, I got stuck when it came to the question below.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Interview officer: “How much do you know about ‘Sessions’ ‘Cookies’ and ‘Tokens’? Could you explain by giving some examples?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Me: Emm… Sure. Well, cookie is emm… Sorry, I think I can answer it. But could I have 1 minute to prepare the answer?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;(Actually even with 5 minutes, I think I still can’t get through it. My brain was simply all blank… Frankly speaking, even I could answer it I think I was only fighting for my ego.)&lt;/p&gt;

&lt;p&gt;Then after 1 minute, I began my speech with some stuttering: “Cookie stores on the client side. Session is kept on server side. Token is authorization / authentication credential that helps querying resources. And uh…” (paused for several seconds)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Interview Officer: Okay, sounds good. Anything else to add? What about the differences between sessions and tokens?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Me: Emm… (paused for another several seconds)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As a result the interview turned into a failed attempt. And after that day of the interview, I’ve set up my mind to study those fundamental knowledge about “Session” “Cookies” and “Tokens”.&lt;/p&gt;
&lt;h2&gt;
  
  
  #The evolutionary history of session
&lt;/h2&gt;

&lt;p&gt;From long ago, our Internet was just a place full of documents for simple browsering purpose. The server doesn’t need to remember “who” and “what”. Every single HTTP request was just a pure request towards document contents.&lt;/p&gt;

&lt;p&gt;Later when users are looking for more interactive functions for example shopping cart and credit card payments, websites started facing a problem which is to memorize and manage the user related information. Like “who” put “what” product into “which” shopping cart.&lt;/p&gt;

&lt;p&gt;This means website needs the ability to distinguish every single user. It’s a challenging task to the servers since HTTP doesn’t really fit in such “stateful” scenario.&lt;/p&gt;

&lt;p&gt;Servers could simply add a “mark” (session id) to each of those who visited / logged-in / purchased. In another word, this “mark” is a random and unique string that is created and remains in memory of the web server and can be attached to the HTTP request. This “mark” is also stored on the user’s browser as so-called “Cookies”. When user started a new request, server will then understand who is requesting.&lt;/p&gt;

&lt;p&gt;Such solution brought convenience to the users, however the servers were under a huge burden of remembering each user’s session id. As a result, hundreds and thousands of session ids were kept on the servers. A web service’s backend be a cluster (or several clusters) containing tons of server nodes and each of them has to store user’s session id.&lt;/p&gt;

&lt;p&gt;Well, this sounds like a “fair” solution by far, isn’t it?&lt;/p&gt;

&lt;p&gt;But what if a user login from “server A” the first time and redirects to another page via “server B” the second time? “server B” doesn’t have the user session id yet… How could “server B” handle such case?&lt;/p&gt;

&lt;p&gt;Now, here comes the role of &lt;a href="https://docs.aws.amazon.com/elasticloadbalancing/latest/application/sticky-sessions.html"&gt;sticky-session&lt;/a&gt; (also check out this &lt;a href="https://www.imperva.com/learn/availability/sticky-session-persistence-and-cookies/"&gt;article&lt;/a&gt;). The simplest solution is to only allow user to stick with “server A” which maintains user’s session id. But what if “server A” crashed and cannot respond to user’s request? (the well-known &lt;a href="https://en.wikipedia.org/wiki/Single_point_of_failure"&gt;“single-point-of-failure”&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KuE5nCcT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/e7bc4878be61102a39f65ddf6e0d7e1a/edbd3/copy_session_id.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KuE5nCcT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/e7bc4878be61102a39f65ddf6e0d7e1a/edbd3/copy_session_id.png" alt="Copy sessions from server A to server B" title="Copy sessions from server A to server B" width="880" height="412"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Copy sessions from server A to server B&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We can copy the session id from “server A” to “server B”. When “server A” crashed, “server B” will still help handle requests. But it’s not yet optimal because doing “copy-paste” between servers are clearly “cost-effective” especially when there are many many users.&lt;/p&gt;

&lt;p&gt;How about we store session ids in another dedicated server as “session server”, away from those “servers” that are providing page routing / rendering. And such server will only maintain the user session ids. To avoid having “single-point-of-failuire”, let’s group multiple “session servers” together as one cluster.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pueXZ9Dx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/e4d225751773885e168dacf513a43e28/edbd3/session_cluster.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pueXZ9Dx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/e4d225751773885e168dacf513a43e28/edbd3/session_cluster.png" alt="Web server cluster and session server cluster" title="Web server cluster and session server cluster" width="880" height="767"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Web server cluster and session server cluster&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Okay, we separated the website servers into “web server cluster” and “session server cluster”. (&lt;a href="https://redis.io"&gt;Redis&lt;/a&gt; and &lt;a href="https://memcached.org"&gt;Memcached&lt;/a&gt; are those popular solutions to session management) Even though the sessions are reliable now, managing this little “session” is yet a big burden to the maintainers no matter what.&lt;/p&gt;

&lt;p&gt;So, is there a simple and feasible way to manage those sessions only on the client side to make both users and maintainers happy? Which can be interpreted as: a user login to the website but the website doesn’t store the user session.&lt;/p&gt;

&lt;p&gt;We can let the server return a “Token” string (the most common example is &lt;a href="https://jwt.io"&gt;JWT&lt;/a&gt;) to each logged-in users similarly to “Cookies”. In order to prevent bad guys faking the “Tokens”, we use a hash algorithm (for example HS256, RS256) and a secret key that only we know to generate a “signature”. This “signature” together with the user id (can also use some other user related information) treated as “Token” is what’s finally stored in the user’s browser.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KXMqtH8I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/896d4269a7f5169fa4af3b9fcf0eea5e/aa132/token.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KXMqtH8I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/896d4269a7f5169fa4af3b9fcf0eea5e/aa132/token.png" alt="Token generation" title="Token generation" width="880" height="360"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Token generation&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When user sends a request together with this token, servers will take some parts (“header” and “payload”) from the token and regenerate the “signature”. If the signature of the given “token” is the same to the regenerated one, then the user can be considered as logged in. Server should fetch and return the user data. Otherwise, authentication should fail.&lt;/p&gt;

&lt;p&gt;Note that,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Signature is not encryption!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This means we can’t put any sensitive data into the “Token”. Because people will still get what’s written in the “Token” easily. The below is an example of “JWT” which looks like already encrypted. But actually it’s just a &lt;a href="https://en.wikipedia.org/wiki/Base64"&gt;Base64&lt;/a&gt; encoded string.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJNZSJ9.Ftkmp-5WXYuhgSya_Ah97SBQ1ffR5WlWl_1lLsK3DyM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With any “Token” decoding tool you could find on the Internet, this “Token” can be decoded into:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ alg: "HS256", typ: "JWT"}.{ userId: "Me" }.[Signature]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait… If this can be decoded and seen by anyone else, then it is never safe, isn’t it?&lt;/p&gt;

&lt;p&gt;Right, if someone stole your token and pretend he is you then server doesn’t know this “someone” is the real you or not.&lt;/p&gt;

&lt;p&gt;In another word,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One with a “valid” token is a “valid” user.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But this indeed removes the burden of servers managing sessions for user since servers just need to authenticate whether the “token” is valid without remembering any sessions. Engineers can now do scalings and maintanences without worrying much about sessions.&lt;/p&gt;

&lt;h2&gt;
  
  
  #More about “Cookies”
&lt;/h2&gt;

&lt;p&gt;Cookies are small pieces of data (no more than 4kb) that websites store on your computer as records of your interactions with them. They’re used by websites to keep track of who you are and to remember things like your indentity information.&lt;/p&gt;

&lt;p&gt;This is how websites are able to remember you as you move between pages and return to the same login screen or the same shopping cart. Nowadays, web apps also utilizes cookies to allow users to save their preferences for instance themes / local settings.&lt;/p&gt;

&lt;p&gt;Some key points of “Cookies”.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maximum 4kb of data stored on user’s computer&lt;/li&gt;
&lt;li&gt;Not able to cross origin but Top-level domain cookies can be shared to Second-level (and higher levels) domain&lt;/li&gt;
&lt;li&gt;Cookies can be expired&lt;/li&gt;
&lt;li&gt;Cookies’ number is limited for each domain&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  #More about “Sessions”
&lt;/h2&gt;

&lt;p&gt;Session is a mechanism to save the clients’ information on the server with a certain data structure. It represents the process of a session between the server and the client.&lt;/p&gt;

&lt;p&gt;For instance, a user session data may contain following information&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;user profile&lt;/li&gt;
&lt;li&gt;user authority and authentication&lt;/li&gt;
&lt;li&gt;user group&lt;/li&gt;
&lt;li&gt;etc&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this way, information stored in the session object will not be lost when the user jumps between the application’s web pages, and it will persist throughout the user’s visiting period.&lt;/p&gt;

&lt;p&gt;However, session will probably be closed when user proactively closes the session, for example closing pages or logging out. To add more, session will also be closed when it expires.&lt;/p&gt;

&lt;p&gt;The server’s session usually needs to collaborate with browser cookies to specify the user’s identity because the browser doesn’t know who this “John Doe” is.&lt;/p&gt;

&lt;p&gt;Thus, what’s most commonly seen inside a cookie value is “session_id” which is a unique identification to help server understand the vistor’s identity to proceed to some further actions (e.g. fetch user data).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NI3K1awN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/672c54091b6763270f5f98621c753e4f/b62b2/browser_server_session.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NI3K1awN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/672c54091b6763270f5f98621c753e4f/b62b2/browser_server_session.png" alt="How browser and server handle session" title="How browser and server handle session" width="880" height="557"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;How browser and server handle session&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let’s take a look at a real world example.&lt;/p&gt;

&lt;p&gt;A user login to a site, the server handles the login request and return the response with a cookie which contains “session_id” in it and gets stored in the user’s browser.&lt;/p&gt;

&lt;p&gt;Then the second time the user redirects himself to a page that requires a login. The request brings the cookie to server. And then the server finds that this user has already logged in, it redirects the user with the target page.&lt;/p&gt;

&lt;p&gt;Some key points of “Sessions”&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“Session” and “Cookies” are under a cooperative relationship&lt;/li&gt;
&lt;li&gt;Able store any kinds of data structure as identification information&lt;/li&gt;
&lt;li&gt;Stores on server side. Safer than cookies&lt;/li&gt;
&lt;li&gt;“Session” can be expired&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  #More about “Tokens”
&lt;/h2&gt;

&lt;p&gt;(The “Tokens” here we talk about is the “Web Tokens”. The BlockChain related tokens are not in this topic)&lt;/p&gt;

&lt;p&gt;“Token” is a series of strings generated by the servers as a token for the user’s request. When the user visits the server for the first time, the server will generate a “Token” using algorithms (for instance, &lt;a href="RS256%5D(https://auth0.com/blog/rs256-vs-hs256-whats-the-difference/)"&gt;HS256 / RS256&lt;/a&gt;) and a secret key according to the unique identifier passed in. Then the “Token” is encoded with &lt;a href="https://en.wikipedia.org/wiki/Base64"&gt;Base64&lt;/a&gt; and returned to the user side. The “Token” can be saved locally as a file or in browser’s memory. In the second time visit, the “Token” will get attached to the requests. And then server will validate the token via the same algorithms and the secret key.&lt;/p&gt;

&lt;p&gt;Some key points of “Tokens”&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Should be attached to every “resource-fetching” HTTP request’s header when the request requires authentication / validation&lt;/li&gt;
&lt;li&gt;No server-side session required&lt;/li&gt;
&lt;li&gt;Supports mobile devices naturally&lt;/li&gt;
&lt;li&gt;“Tokens” can be expired&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"&gt;CORS&lt;/a&gt; is made available especially when we need to collaborate with other public services or applications or even devices&lt;/li&gt;
&lt;li&gt;Able to circumvent &lt;a href="https://en.wikipedia.org/wiki/Cross-site_request_forgery"&gt;CSRF&lt;/a&gt; because “Token” is authenticated on the server-side and can be expired&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  #Access token
&lt;/h3&gt;

&lt;p&gt;An “Access token” is the “Token” mentioned before which is carried together with the requests and as a credential for fetching resources via API endpoints. It has a fixed expire to make user re-authenticate periodically which prevents security issues to a certain extent.&lt;/p&gt;

&lt;p&gt;A simple “Access token” can be composed by&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;unique identifier&lt;/li&gt;
&lt;li&gt;timestamp&lt;/li&gt;
&lt;li&gt;signature (a generated string based on )&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zVVhQHkd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/6a1f4dbc61aae8029022a48005ba6715/2c1f1/access_token_process_flow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zVVhQHkd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/6a1f4dbc61aae8029022a48005ba6715/2c1f1/access_token_process_flow.png" alt="How access token works" title="How access token works" width="880" height="518"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;How access token works&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  #Refresh token
&lt;/h3&gt;

&lt;p&gt;A “Refresh token” is a good helper to ask server to regenerate a new “Access token”. It’s considered as a convenient solution because generating the “Access token” requires user’s id and password everytime.&lt;/p&gt;

&lt;p&gt;Same to “Access token”, “Refresh token” also has an expiry date attached to it but “Refresh token” has a longer expiry. Once “Refresh token” expired, user has to redo the login to get a pair of new “Access token” and “Refresh token”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--b8-WhrLl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/ad9d47bdcc7154646168b74f70afc9b2/b50c7/refresh_token_process_flow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b8-WhrLl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/ad9d47bdcc7154646168b74f70afc9b2/b50c7/refresh_token_process_flow.png" alt="How refresh token works" title="How refresh token works" width="880" height="1055"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;How refresh token works&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Usually, “Refresh token’s” expiry datetime is stored in the database, it’ll be authenticated and validated only when re-issuing the “Access token”. Thus, it has a very minimal effect to the backend server performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  #JSON Web Token (JWT)
&lt;/h3&gt;

&lt;p&gt;A “JWT” string contains&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Header (hash algo for signature)&lt;/li&gt;
&lt;li&gt;Payload (a user data structure containing the unique indentifier)&lt;/li&gt;
&lt;li&gt;Signature (a generated string based on &lt;code&gt;Header&lt;/code&gt; and &lt;code&gt;Payload&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;According to &lt;a href="https://jwt.io/introduction"&gt;jwt.io&lt;/a&gt;,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To make it short, JWT is a solution to provide authenticated info for crossing origins. The official document has done a very clear and in-depth explanation about JWT’s features. Allow me skip re-explaining.&lt;/p&gt;

&lt;p&gt;“JWT” truly brought us engineers a lot of advatanges. However, its security issue is a nonnegligible topic. There’s already a good alternative &lt;a href="https://paseto.io"&gt;PASETO&lt;/a&gt; to replace “JWT”.&lt;/p&gt;

&lt;p&gt;For those who are interested in the “JTW” securities, here’re some good articles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://curity.io/resources/learn/jwt-best-practices/"&gt;https://curity.io/resources/learn/jwt-best-practices/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-bad-standard-that-everyone-should-avoid"&gt;https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-bad-standard-that-everyone-should-avoid&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/"&gt;http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  #In the end
&lt;/h2&gt;

&lt;p&gt;Even this article has already covered quite a few knowledge points of sessions cookies and tokens, but there’re a lot more to investigate.&lt;/p&gt;

&lt;p&gt;As for the interview I took that time, I think I was good at interactions and double-confirming questions which contributed to a smooth interview process.&lt;/p&gt;

&lt;h2&gt;
  
  
  #References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/elasticloadbalancing/latest/application/sticky-sessions.html"&gt;https://docs.aws.amazon.com/elasticloadbalancing/latest/application/sticky-sessions.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.imperva.com/learn/availability/sticky-session-persistence-and-cookies/"&gt;https://www.imperva.com/learn/availability/sticky-session-persistence-and-cookies/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Single_point_of_failure"&gt;https://en.wikipedia.org/wiki/Single_point_of_failure&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>network</category>
      <category>interview</category>
    </item>
    <item>
      <title>What do these console.log print out?</title>
      <dc:creator>Yanze Dai</dc:creator>
      <pubDate>Mon, 02 May 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/pitayan/what-do-these-consolelog-print-out-52i5</link>
      <guid>https://dev.to/pitayan/what-do-these-consolelog-print-out-52i5</guid>
      <description>&lt;p&gt;Originally published on &lt;a href="https://pitayan.com/posts/8-javascript-quiz-that-may-confuse-you"&gt;Pitayan | What do these console.log print out?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Come to the original site for a better reading experience.&lt;/p&gt;




&lt;p&gt;These days, I was preparing a small game for our team's tech workshop. Thought it'd be a good opportunity of introducing the some fundamental and tricky stuffs around JavaScript. So I made 8 quiz to our team members. And hope they could solve them within 15 min. Eventually, it took all of them over 20 minutes to complete and most of them could solve 4-5 questions correctly.&lt;/p&gt;

&lt;p&gt;You can take it as just a small test, each quiz has answer attached to the end of the code. Try to answer them first and then look at the answers. Good luck.&lt;/p&gt;

&lt;h2&gt;
  
  
  #What do these console.log print out?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  #No. 1 -- Doctor Pavlov has a dog
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function Animal(){ 
  this.type = "animal"
}

function Dog(){ 
  this.name = "dog"
}

Dog.prototype = new Animal()

var PavlovPet = new Dog(); 

console.log(PavlovPet. __proto__ === Dog.prototype)
console.log(Dog.prototype. __proto__ === Animal.prototype)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Answer for No. 1
&lt;/h1&gt;

&lt;p&gt;Very basic stuff about the prototype chain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Output
true
true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h3&gt;
  
  
  #No. 2 -- Be careful with the "sort"
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var arr = [5, 22, 14, 9];

console.log(arr.sort());
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Answer for No. 2
&lt;/h1&gt;

&lt;p&gt;Sorry, not [5, 9, 14, 22]. Each element is converted into string and then comparing the sequence of UTF-16 value.&lt;/p&gt;

&lt;p&gt;Check this out: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort"&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Output
[14, 22, 5, 9]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #No. 3 -- Closure and event loop
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for (var i = 0; i &amp;lt; 3; i++) {
  const log = () =&amp;gt; {
    console.log(i)
  }
  setTimeout(log, 100)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Answer for No. 3
&lt;/h1&gt;

&lt;p&gt;It prints out 3 thrice since setTimout puts that &lt;code&gt;log&lt;/code&gt; function to the next macro task queue&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Output
3
3
3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #No. 4 -- There's indentation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function createNewArray(item) {
  return
    [item]
}

console.log(createNewArray(0))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Answer for No. 4
&lt;/h1&gt;

&lt;p&gt;This causes an error. Can't return value with break-line and indentation together&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Uncaught SyntaxError: Invalid or unexpected token
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #No. 5 -- What's inside the "numbers"
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const length = 4
const numbers = []
for (var i = 0; i &amp;lt; length; i++);{
  numbers.push(i + 1)
}

console.log(numbers)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Answer for No. 5
&lt;/h1&gt;

&lt;p&gt;This needs a pair of sharp eyes. See that semicolon between the parentheses and curly bracket?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Output
[5]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #No. 6 -- No length
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const clothes = ['shirt', 'socks', 'jacket', 'pants', 'hat']
clothes.length = 0

console.log(clothes[3])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Answer for No. 3
&lt;/h1&gt;

&lt;p&gt;This is equivalant to removing all elements from the array&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Output
undefined
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #No. 7 -- Variable went crazy
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var a = 1
function output () {
    console.log(a)
    var a = 2
    console.log(a)
}
console.log(a)
output()
console.log(a)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Answer for No. 7
&lt;/h1&gt;

&lt;p&gt;First output: using the global &lt;code&gt;var a&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Second output: the first one in the &lt;code&gt;function output()&lt;/code&gt; using before declaration should be undefined&lt;/p&gt;

&lt;p&gt;Third output: print out after the declaration. Nothing special.&lt;/p&gt;

&lt;p&gt;Forth output: &lt;code&gt;var a&lt;/code&gt; never got changed by &lt;code&gt;function output()&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Output
1
undefined
2
1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #No. 8 -- There's an accidental declaration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function foo() {
    let a = b = 0
    a++
    return a
}

foo()
console.log(typeof a)
console.log(typeof b)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Answer for No. 3
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;let a&lt;/code&gt; is a local variable. &lt;code&gt;typeof a&lt;/code&gt; is checking undeclared variable.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;b&lt;/code&gt; is a global variable which value is assign in &lt;code&gt;function foo()&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Output
undefined
number
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #In the end
&lt;/h2&gt;

&lt;p&gt;Thanks so much for reading! Have you got them all correct?&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
    <item>
      <title>8 Javascript quiz that may confuse you</title>
      <dc:creator>Yanze Dai</dc:creator>
      <pubDate>Mon, 02 May 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/pitayan/8-javascript-quiz-that-may-confuse-you-2igm</link>
      <guid>https://dev.to/pitayan/8-javascript-quiz-that-may-confuse-you-2igm</guid>
      <description>&lt;p&gt;Originally published on &lt;a href="https://pitayan.com/posts/8-javascript-quiz-that-may-confuse-you/"&gt;Pitayan | 8 Javascript quiz that may confuse you&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;These days, I was preparing a small game for our team’s tech workshop. Thought it’d be a good opportunity of introducing the some fundamental and tricky stuffs around JavaScript. So I made 8 quiz to our team members. And hope they could solve them within 15 min. Eventually, it took all of them over 20 minutes to complete and most of them could solve 4-5 questions correctly.&lt;/p&gt;

&lt;p&gt;You can take it as just a small test, each quiz has answer attached to the end of the code. Try to answer them first and then look at the answers. Good luck.&lt;/p&gt;

&lt;h2&gt;
  
  
  #What do these console.log print out?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  #No. 1 – Doctor Pavlov has a dog
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt; 
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;animal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt; 
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;PavlovPet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PavlovPet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;__proto__&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;__proto__&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://pitayan.com/posts/8-javascript-quiz-that-may-confuse-you/#no-1-doctor-pavlov-has-a-dog"&gt;Answer for #1&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  #No. 2 – Be careful with the “sort”
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://pitayan.com/posts/8-javascript-quiz-that-may-confuse-you/#no-2-be-careful-with-the-sort"&gt;Answer for #2&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  #No. 3 – Closure and event loop
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://pitayan.com/posts/8-javascript-quiz-that-may-confuse-you/#no-3-closure-and-event-loop"&gt;Answer for #3&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  #No. 4 – There’s indentation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;createNewArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;createNewArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://pitayan.com/posts/8-javascript-quiz-that-may-confuse-you/#no-4-there-s-indentation"&gt;Answer for #4&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  #No. 5 – What’s inside the “numbers”
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;);{&lt;/span&gt;
  &lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://pitayan.com/posts/8-javascript-quiz-that-may-confuse-you/#no-5-what-s-inside-the-numbers"&gt;Answer for #5&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  #No. 6 – No length
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clothes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;shirt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;socks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jacket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pants&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nx"&gt;clothes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clothes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://pitayan.com/posts/8-javascript-quiz-that-may-confuse-you/#no-6-no-length"&gt;Answer for #6&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  #No. 7 – Variable went crazy
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://pitayan.com/posts/8-javascript-quiz-that-may-confuse-you/#no-7-variable-went-crazy"&gt;Answer for #7&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  #No. 8 – There’s an accidental declaration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://pitayan.com/posts/8-javascript-quiz-that-may-confuse-you/#no-8-there-s-an-accidental-declaration"&gt;Answer for #8&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #In the end
&lt;/h2&gt;

&lt;p&gt;Thanks so much for reading! Have you got them all correct?&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>quiz</category>
    </item>
    <item>
      <title>Learning tmux as a beginner</title>
      <dc:creator>Yanze Dai</dc:creator>
      <pubDate>Sat, 30 Apr 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/pitayan/learning-tmux-as-a-beginner-4hh6</link>
      <guid>https://dev.to/pitayan/learning-tmux-as-a-beginner-4hh6</guid>
      <description>&lt;p&gt;Originally published on &lt;a href="https://pitayan.com/posts/learning-tmux-as-a-beginner"&gt;Pitayan | Learning tmux as a beginner&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Nowadays, Tmux has become into the everyday tool in my workdays. I always wanted to summarize the Tmux usage from long ago when I began to use it. So this article is pretty much what I have started with as a Tmux beginner.&lt;/p&gt;
&lt;h2&gt;
  
  
  #Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What consists of Tmux&lt;/li&gt;
&lt;li&gt;
What is a Tmux session

&lt;ul&gt;
&lt;li&gt;1. Create a session&lt;/li&gt;
&lt;li&gt;2. Kill a session&lt;/li&gt;
&lt;li&gt;3. Kill all of the sessions&lt;/li&gt;
&lt;li&gt;4. Switch between sessions&lt;/li&gt;
&lt;li&gt;5. Rename session&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
What is a Tmux window

&lt;ul&gt;
&lt;li&gt;1. Create a new window&lt;/li&gt;
&lt;li&gt;2. Switch between windows&lt;/li&gt;
&lt;li&gt;3. Search the windows&lt;/li&gt;
&lt;li&gt;4. List all of the windows in this session&lt;/li&gt;
&lt;li&gt;5. Rename current window&lt;/li&gt;
&lt;li&gt;6. Close current window&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
What is a Tmux Pane?

&lt;ul&gt;
&lt;li&gt;1. Split pane vertically / horizontally&lt;/li&gt;
&lt;li&gt;2. Kill a pane&lt;/li&gt;
&lt;li&gt;3. Switch between panes&lt;/li&gt;
&lt;li&gt;4. Move the current pane to a new window&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  #What consists of Tmux?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Session&lt;/li&gt;
&lt;li&gt;Window&lt;/li&gt;
&lt;li&gt;Pane&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  #What is a Tmux session?
&lt;/h2&gt;

&lt;p&gt;The "dialog" that's been kept by Tmux for running tasks which can be resumed later disconnection.&lt;/p&gt;
&lt;h3&gt;
  
  
  #1. Create a session
&lt;/h3&gt;

&lt;p&gt;Creating a session in Tmux is very semantic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ tmux new -s &amp;lt;session_name&amp;gt;

# e.g.
$ tmux new -s helloworld
$ tmux new -s great
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #2. Kill a session
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;&lt;code&gt;-t&lt;/code&gt;&lt;/strong&gt; flag here means "target". Put the target session name after it to delete the session from Tmux&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ tmux kill-session -t &amp;lt;session_name&amp;gt;

# e.g.
$ tmux kill-session -t helloworld
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #3. Kill all of the sessions
&lt;/h3&gt;

&lt;p&gt;The command &lt;code&gt;kill-server&lt;/code&gt; seems a bit confusing. But Tmux does have a server running behind the scenes to be able to keep the located processes when the session is detached. So, killing a Tmux server means deleting all saved sessions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ tmux kill-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #4. Switch between sessions
&lt;/h3&gt;

&lt;p&gt;It's useful when we are in a particular session but want to transfer to another session we used.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ tmux switch -t &amp;lt;session_name&amp;gt;

# e.g.
$ tmux switch -t great
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #5. Rename session
&lt;/h3&gt;

&lt;p&gt;Edit the session name after we created it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ tmux switch -t &amp;lt;from&amp;gt; &amp;lt;to&amp;gt;

# e.g.
$ tmux rename -t great hi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #What is a Tmux Window?
&lt;/h2&gt;

&lt;p&gt;The "child" under a Tmux Session. A session can have multiple windows ("children") to switch from.&lt;/p&gt;

&lt;p&gt;To manipulate the window, we need to use the "Prefix" shortcuts. By default, Tmux uses &lt;code&gt;Ctrl+b&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  #1. Create a new window
&lt;/h3&gt;

&lt;p&gt;This will create a new window and leave a number of the window we created to the Tmux bottom status line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ctrl + b + c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;0:zsh&lt;/code&gt; is the first window, &lt;code&gt;1:zsh&lt;/code&gt; is the second window.&lt;/p&gt;

&lt;h3&gt;
  
  
  #2. Switch between windows
&lt;/h3&gt;

&lt;p&gt;We could choose the target window by specifying its number.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ctrl + b + &amp;lt;window_number&amp;gt;

# e.g.
Ctrl + b + 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #3. Search the windows
&lt;/h3&gt;

&lt;p&gt;We could look for the windows we created. The Tmux will go search the output / printout in the terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ctrl + b + f
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #4. List all of the windows in this session
&lt;/h3&gt;

&lt;p&gt;The result screen is actually the same to search but with all of the windows we have.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ctrl + b + w
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #5. Rename current window
&lt;/h3&gt;

&lt;p&gt;By default, the window we created with &lt;code&gt;Ctrl+b+c&lt;/code&gt; will have a name like "0:zsh" "1:shell". Sometimes we need special names to distinguish those windows (like naming the sessions) in a rather semantic way.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ctrl + b + ,
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #6. Close current window
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ctrl + b + &amp;amp;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #What is a Tmux Pane?
&lt;/h2&gt;

&lt;p&gt;Instead of Tmux windows to switch back and forth, a Tmux pane can help split the window into certain smaller blocks within the same screen. So that we could retain the information on the same screen.&lt;/p&gt;

&lt;h3&gt;
  
  
  #1. Split pane vertically / horizontally
&lt;/h3&gt;

&lt;p&gt;Tmux makes it very easy to understand about pane splitting. The symbol &lt;code&gt;%&lt;/code&gt; and &lt;code&gt;"&lt;/code&gt; vividly explains how we are gonna split our screen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# vertical split
Ctrl + b + "

# horizontal split
Ctrl + b + %
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #2. Kill a pane
&lt;/h3&gt;

&lt;p&gt;Usually when we run nothing in the terminal, we could close it immediately with &lt;code&gt;Ctrl+d&lt;/code&gt; for most of the terminals. However if we are under some program like &lt;code&gt;Vim&lt;/code&gt; or &lt;code&gt;SSH&lt;/code&gt; and still hope to kill the pane forcefully, this will come into help.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ctrl + b + x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #3. Switch between panes
&lt;/h3&gt;

&lt;p&gt;Jump around the panes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ctrl + b + o
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also have numbers for each panes. Display the number of each pane and type the number to select the target pane.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# display pane number
Ctrl + b + q

# e.g.
Ctrl + b + q &amp;amp; 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #4. Move the current pane to a new window
&lt;/h3&gt;

&lt;p&gt;Sometimes the pane we created is maybe too small to showcase everything in that terminal. We might need to consider moving the pane to a new window.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ctrl + b + !
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  #Summary
&lt;/h2&gt;

&lt;p&gt;I personally think Tmux is a very good looking and helpful tool to allow everyone to control their terminals with only keyboards. Nowadays terminal apps like "iTerm" "cmder" all provided features similar to Tmux's "window" and "pane". Sometimes, these features are even more convenient than Tmux.&lt;/p&gt;

&lt;p&gt;Tmux is really a powerful tool. But it needs time for us to digest the shortcut keys which is seemingly a "learning" curve to us all so that we could finally master using this powerful tool.&lt;/p&gt;

</description>
      <category>shell</category>
      <category>tools</category>
    </item>
    <item>
      <title>Remake Pitayan Blog (Part 2)</title>
      <dc:creator>Yanze Dai</dc:creator>
      <pubDate>Mon, 25 Apr 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/pitayan/remake-pitayan-blog-part-2-2g7n</link>
      <guid>https://dev.to/pitayan/remake-pitayan-blog-part-2-2g7n</guid>
      <description>&lt;p&gt;Originally published on &lt;a href="https://pitayan.com/posts/remake-pitayan-blog-part-2"&gt;Pitayan | Remake Pitayan Blog (Part 2)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In 2021, I wrote an article of &lt;a href="https://dev.to/posts/remake-pitayan-blog"&gt;Remake Pitayan Blog (part 1)&lt;/a&gt; sharing an idea of re-constructing my blog with a better design. And finally at the same timing when this article was published, the project was initialized.&lt;/p&gt;

&lt;p&gt;This project went quite a long way for over 10 months. I never thought this whole project would ever spend so much time to complete. As of this day when this article is written, Pitayan blog is officially updated to this new version.&lt;/p&gt;

&lt;h2&gt;
  
  
  #Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Setting up the objectives&lt;/li&gt;
&lt;li&gt;Migrating from "Gridsome" to "Gatsby"&lt;/li&gt;
&lt;li&gt;
The UI design

&lt;ul&gt;
&lt;li&gt;Using Rotala.css?&lt;/li&gt;
&lt;li&gt;Color Palette&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
Some cool features

&lt;ul&gt;
&lt;li&gt;The selection popover menu&lt;/li&gt;
&lt;li&gt;Medium-link picture magnifier&lt;/li&gt;
&lt;li&gt;Dark and light mode&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;@pitayan/gatsby-theme-pitayan&lt;/li&gt;
&lt;li&gt;What's next?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  #Setting up the objectives
&lt;/h2&gt;

&lt;p&gt;I can only use my spare time on my personal projects. And almost all of my time were spent on function developments and fixing bugs. As a consequence, those intermittent contributions caused many back and forth due to lacking of appropriate objectives ahead of starting those projects.&lt;/p&gt;

&lt;p&gt;Thus this time, I setup some practical objectives and list out the necessary "todos" under each of its items. I know that if I don't keep a track on what to do and what has been done somewhere, then resuming the process of this project later after some break may become very problematic.&lt;/p&gt;

&lt;p&gt;To begin with creating objectives, I wrote down some notes around the following aspects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The blog new UI design&lt;/li&gt;
&lt;li&gt;Implement the blog with Gatsby (as a plugin)&lt;/li&gt;
&lt;li&gt;Create necessary pages&lt;/li&gt;
&lt;li&gt;Migrate articles from the current blog&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(And actually in the next following months, the development kept running toward that direction without any turnings.)&lt;/p&gt;

&lt;p&gt;For managing objectives, I utilized &lt;a href="https://github.com/orgs/Pitayan/projects/1"&gt;Github "Projects"&lt;/a&gt; feature to help me manage issues and notes. As you could see there are still quite a few more tasks to do for this project. Although some of the tasks are not very fine-grained, they are yet helpful every time when I hope to recall the latest progress.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fLscHqo_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/4bdefce4ffe9c8a174975abb24e2a810/1a33b/github_projects.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fLscHqo_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/4bdefce4ffe9c8a174975abb24e2a810/1a33b/github_projects.png" alt="Github Projects for issues and notes" title="Github Projects for issues and notes" width="880" height="637"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Github Projects for issues and notes&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  #Migrating from "Gridsome" to "Gatsby"
&lt;/h2&gt;

&lt;p&gt;The previous &lt;a href="https://dev.to/posts/remake-pitayan-blog"&gt;article&lt;/a&gt; mentioned why to migrate away from &lt;a href="https://gridsome.org"&gt;Gridsome&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I want to migrate to Gatsby for a bigger community.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is a very interesting but a very time-consuming step to me. But I believe the outcome of this step will eventually turn out to be the right decision.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gatsbyjs.org"&gt;Gatsby&lt;/a&gt; provides a solid user guide that let me get started quickly without digging into their source code for solutions. And meanwhile, &lt;a href="https://gatsbyjs.org"&gt;Gatsby&lt;/a&gt;'s rich plugin library helps extending the functions rather easily(even with only official plugins).&lt;/p&gt;

&lt;p&gt;Since it's a complete rewrite, I followed some example repos to scratch my own project. (Want to say thanks to these repo owners and contributors)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/JorgeX/gatsby-theme-novela"&gt;gatsby-theme-novela&lt;/a&gt; (Unfortunately, the original repo was out of maintenance and removed by the owner. This is a fork)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/rossettiquette/gatsby-starter-blog-dev-mdx"&gt;gatsby-starter-blog-dev-mdx&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Sridatta19/gatsby-starter-tailwind-mdx-blog"&gt;gatsby-starter-tailwind-mdx-blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/rwieruch/gatsby-mdx-blog-starter-project"&gt;gatsby-mdx-blog-starter-project&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These years, many CSS frameworks claims their helpful features are able to solve developers' pain points. At first, frameworks using CSS-in-JS like &lt;a href="https://styled-components.com"&gt;styled-components&lt;/a&gt; &amp;amp; &lt;a href="https://emotion.sh/docs/introduction"&gt;emotion&lt;/a&gt; were taken into consideration judging their community relativity toward React.js.&lt;/p&gt;

&lt;p&gt;I started using &lt;a href="https://tailwindcss.com"&gt;Tailwindcss&lt;/a&gt; from long ago, and felt it extremely handy and flexible (maybe I'm just quite used to it already). So, in this project, I want to try with &lt;a href="https://tailwindcss.com"&gt;Tailwindcss&lt;/a&gt; again.&lt;/p&gt;

&lt;p&gt;And for the core plugins, the following ones are chosen based upon the official starters. (Guess almost every developer would pick these up no matter what)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-plugin-mdx"&gt;gatsby-plugin-mdx&lt;/a&gt;: need to allow using React components in Markdown source for a quick feature enhancement&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-plugin-sharp"&gt;gatsby-plugin-sharp&lt;/a&gt;: Image quality control&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-plugin-image"&gt;gatsby-plugin-image&lt;/a&gt;: Provides the images component&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-remark-images"&gt;gatsby-remark-images&lt;/a&gt;: Process markdown images&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-transformer-yaml"&gt;gatsby-transformer-yaml&lt;/a&gt;: Process Yaml file (used for author profile)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-transformer-sharp"&gt;gatsby-transformer-sharp&lt;/a&gt;: Image quality control for markdown images&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-source-filesystem"&gt;gatsby-source-filesystem&lt;/a&gt;: You know, the very necessary plugin...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, with some extra "personal-favored" plugins, I created a rough repo outline. Check out to this commit &lt;code&gt;0d23f502cb2538e51e75ea7589b1ca53722c121f&lt;/code&gt; to see the beginning setup (&lt;a href="https://github.com/Pitayan/gatsby-theme-pitayan/commit/0d23f502cb2538e51e75ea7589b1ca53722c121f"&gt;Github link here&lt;/a&gt;).&lt;/p&gt;
&lt;h2&gt;
  
  
  #The UI design
&lt;/h2&gt;

&lt;p&gt;The previous Pitayan blog design is very good-looking to me. Back then, it was made to mimic &lt;a href="https://medium.com"&gt;Medium.com&lt;/a&gt; and &lt;a href="https://dev.to"&gt;Dev Community&lt;/a&gt; to a certain extent (perhaps only the color schemes :p).&lt;/p&gt;

&lt;p&gt;But frankly speaking, creating a new design out of the thin air is quite challenging to an engineer without much of design knowledge like me. Thus this time when I started working on the designs, I almost copied 100% of &lt;a href="https://novela.narative.co"&gt;Novela&lt;/a&gt;'s layout but added some personal flavors to make the difference. Which the "difference" is actually to bring the previous designs like "page footer" &amp;amp; "post meta" etc to the new design.&lt;/p&gt;

&lt;p&gt;I now have only one comment for this decision:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Experience is a reliable beacon.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--phnhiB4l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/0f2ad3523ca84bc95786d851de3868e8/40e3d/novela.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--phnhiB4l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/0f2ad3523ca84bc95786d851de3868e8/40e3d/novela.png" alt="The Novela blog design, this is really good-looking" title="The Novela blog design, this is really good-looking" width="880" height="490"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The Novela blog design, this is really good-looking&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I wanted to log all of those beautiful designs somewhere like a Github issue. I made one &lt;a href="https://github.com/Pitayan/gatsby-theme-pitayan/issues/2"&gt;here&lt;/a&gt; but it's a pity that the progress was never to date...&lt;/p&gt;
&lt;h3&gt;
  
  
  #Using Rotala.css?
&lt;/h3&gt;

&lt;p&gt;I still remember my CSS project in 2019: &lt;a href="https://github.com/daiyanze/rotala"&gt;Rotala.css&lt;/a&gt; which is used by the previous Pitayan blog. This little framework seems very handy at first because it provides lots of useful CSS definitions to extend upon, especially the typographical designs.&lt;/p&gt;

&lt;p&gt;Here is example how I implemented the classes for the components. Such implementation style is exactly what &lt;a href="https://rotalacss.com/docs/#why-made-it-this-way"&gt;Rotala.css&lt;/a&gt; recommends (by using &lt;code&gt;@apply&lt;/code&gt; keyword to mix classes).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.site-tag {
  @apply rounded-sm;
  @apply py-0.5 px-1;
  @apply text-sm;
  @apply text-gray-800;
  @apply bg-gray-200;
  @apply hover:bg-gray-300;
  @apply transition-colors;
  @apply duration-150;
  @apply ease-in-out;

  /* Dark Mode */
  @apply dark:hover:bg-gray-700;
  @apply dark:bg-gray-800;
  @apply dark:text-gray-400;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although this is a really cool feature to reply upon, it seems &lt;a href="https://tailwindcss.com"&gt;Tailwindcss&lt;/a&gt; prefers users to handle their classes in the HTML template.&lt;/p&gt;

&lt;h3&gt;
  
  
  #Color Palette
&lt;/h3&gt;

&lt;p&gt;The color of the new design is just the default setting of &lt;a href="https://tailwindcss.com"&gt;Tailwindcss&lt;/a&gt;. The default palette is already very eye-comfortable, thought it'd be not that necessary to change that so early.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;gray&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;500&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;red&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;500&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;yellow&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;500&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;green&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;500&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;blue&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;500&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;indigo&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;500&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;purple&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;500&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;pink&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;500&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By the way, changing the colors with &lt;a href="https://tailwindcss.com"&gt;Tailwindcss&lt;/a&gt; is just another piece of cake. Overriding the theme settings in the &lt;code&gt;tailwind.config.js&lt;/code&gt; will do the trick.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// tailwind.config.js
module.exports = {
  ...
  theme: {
    colors: {
      primary: {
        ...
      },
      red: {
        ...
      },
      green: {
        ...
      },
      ...
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  #Some cool features
&lt;/h1&gt;

&lt;h2&gt;
  
  
  #The selection popover menu
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://medium.com"&gt;Medium&lt;/a&gt; has a popover menu displaying right above the text content you selected. When it pops up, you could highlight the text and add comments (and even share it to Twitter). Isn't it a wonderful feature?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FwxketgS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/e5056363cc3733c7ebc2434073b2c41b/95c9c/popover_menu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FwxketgS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/e5056363cc3733c7ebc2434073b2c41b/95c9c/popover_menu.png" alt="The Medium popover menu example" title="The Medium popover menu example" width="880" height="293"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The Medium popover menu example&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Such feature also exists in the &lt;a href="https://novela.narative.co"&gt;Novela&lt;/a&gt; blog. It doesn't support text highlight because it requires backend data. But instead, you could copy the selected text and share it to Twitter. So I decided to mimic the Novela's selection popover feature. In this article, you might already noticed this feature but note that the only available area is this article content itself.&lt;/p&gt;

&lt;p&gt;I referred to some community React libraries &lt;a href="https://github.com/mvanlonden/react-selection-popover"&gt;react-selection-popover&lt;/a&gt; &amp;amp; &lt;a href="https://github.com/juliankrispel/react-text-selection-popover"&gt;react-text-selection-popover&lt;/a&gt;. They offered great example of how to detect selection and calculate the positions. Anyhow in the end, I have to create my own plugin / hooks to introduce this feature into the blog theme.&lt;/p&gt;

&lt;p&gt;The reason of doing this is pretty simple: neither of those 2 libraries work perfectly in my case.&lt;/p&gt;

&lt;p&gt;In order to make it work as expected, I created a hook to meet my demands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function useTextSelection (
  container: HTMLElement = document.body,
  offsetWidth = 0,
  offsetHeight = 0,
  lineHeightDelta = 32
): { left: number top: number textContent: string }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function returns &lt;code&gt;left&lt;/code&gt; &lt;code&gt;top&lt;/code&gt; and &lt;code&gt;textContent&lt;/code&gt;. To position the popover, just set the popover mask to &lt;code&gt;absolute&lt;/code&gt; together with its left and top values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div className="selection-popover" style={{ left, top }}&amp;gt;
  ...
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;container&lt;/code&gt; is the HTML element target that holds your selection content. It is a relative anchor of the selection popover container. By default, the &lt;code&gt;document.body&lt;/code&gt; should be a decent container. However usually, it's depending on how you gonna define your popover component.&lt;/p&gt;

&lt;p&gt;In my case, since the popover component has to stay as descendent of the markdown content(the MDX container), it's better just to use that content tag as container.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;offsetWidth&lt;/code&gt; and &lt;code&gt;offsetHeight&lt;/code&gt; are used for centering the popover container. They don't have to be static values as you could grab those attributes from the HTML tag &lt;code&gt;const { width, height } = targetContainer.getBoundingClientRect()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the short feature, I may create a new repo to make everyone accessible to this useful plugin. By far, the source code is also a good example I presume for those who wants to have a selection popover component in their page.&lt;/p&gt;

&lt;h2&gt;
  
  
  #Medium-like picture magnifier
&lt;/h2&gt;

&lt;p&gt;There's a ready-to-use library called &lt;a href="https://github.com/francoischalifour/medium-zoom"&gt;medium-zoom&lt;/a&gt; that reproduced the feature of the Medium.com's picture zoom-in. The time when I found it, it made me so happy that I don't have to create a plugin myself to achieve the feature.&lt;/p&gt;

&lt;p&gt;Guess there's no need to talk more about this feature. Just feel the power of it by click the picture below (or any other pictures in the article page).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZT5ri251--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/deb047058f213a25e36b7f919d62d167/4be17/medium_zoom.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZT5ri251--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/deb047058f213a25e36b7f919d62d167/4be17/medium_zoom.png" alt="This picture will pop out like a modal" title="This picture will pop out like a modal" width="880" height="552"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;This picture will pop out like a modal&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Amazing, isn't it?&lt;/p&gt;
&lt;h2&gt;
  
  
  #Dark and light mode
&lt;/h2&gt;

&lt;p&gt;Like some document sites such as &lt;a href="https://vuejs.org"&gt;vuejs.org&lt;/a&gt;, Pitayan.com now has supported &lt;em&gt;dark-mode&lt;/em&gt; with the Tailwind's builtin feature. It affects not only the usual components for site layout but also the code highlight.&lt;/p&gt;

&lt;p&gt;Remember Tailwind's &lt;code&gt;dark&lt;/code&gt; variable? It is the key to making styles inverted under dark-mode.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@apply text-gray-800;

/** Dark Mode */
@apply dark:text-gray-400;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may have noticed the "sun" icon ☀️ in the top navigation bar, it triggers the theme to toggle between light and dark. (Believe you'll be enjoying using the dark-mode for protecting eyesight 🤓)&lt;/p&gt;

&lt;h1&gt;
  
  
  #@pitayan/gatsby-theme-pitayan
&lt;/h1&gt;

&lt;p&gt;Now the Pitayan.com provides a Gatsby theme plugin so that everyone else can build their own Gatsby blog with our theme.&lt;/p&gt;

&lt;p&gt;Check out this Github repo: &lt;a href="https://github.com/Pitayan/gatsby-theme-pitayan"&gt;Pitayan/gatsby-theme-pitayan&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Following a quick installation which is also mentioned in the README file. The sad part is that it's only a plugin rather than a startup template. It still requires some more steps to get it to run locally.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm install --save-dev gatsby @pitayan/gatsby-theme-pitayan react@17 react-dom@17
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Besides, as you may noticed, at the moment it supports React 17 instead of 18 because the &lt;code&gt;peerDependency&lt;/code&gt; of gatsby-plugin-mdx requires &lt;code&gt;@mdx-js/mdx: ^1.0.0&lt;/code&gt;. Let's wait until they upgrade their version dependencies. Or maybe we could force using the latest React during NPM modules installation to circumvent the warnings.&lt;/p&gt;

&lt;h1&gt;
  
  
  #What's next?
&lt;/h1&gt;

&lt;p&gt;Finally, the new theme of Pitayan.com is released. Although there're still some bugs within the theme, they'll be fixed any day soon.&lt;/p&gt;

&lt;p&gt;I think what's more important to the site now is automate the release process. Believe any day soon in the future, all I need to do for publishing a new article is just "write content" and "create PR". And then it should merge the PR automatically by a Github scheduler. Since the Pitayan.com deploys with &lt;a href="https://netlify.com"&gt;Netlify&lt;/a&gt;, any commits to the &lt;code&gt;master&lt;/code&gt; branch will trigger a new build.&lt;/p&gt;

&lt;p&gt;I'll be publising a part-3 to introduce this automation as the last step of the "remake". Hope I could complete this as soon as possible (No more procrastinations 😆).&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Remake Pitayan Blog (Part 1)</title>
      <dc:creator>Yanze Dai</dc:creator>
      <pubDate>Fri, 25 Jun 2021 00:00:00 +0000</pubDate>
      <link>https://dev.to/pitayan/remake-pitayan-blog-part-1-fkf</link>
      <guid>https://dev.to/pitayan/remake-pitayan-blog-part-1-fkf</guid>
      <description>&lt;p&gt;Originally published on &lt;a href="https://pitayan.com/posts/remake-pitayan-blog"&gt;Pitayan | Remake Pitayan Blog (Part 1)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recently I've decided to remake this whole blog to improve its workflow and UI/UX. This article will uncover my story of creating this blog and also some thoughts about the "remake" approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  #TLDR;
&lt;/h2&gt;




&lt;h1&gt;
  
  
  #The beginning
&lt;/h1&gt;

&lt;p&gt;In 2020, I spent some weeks on building a tech blog &lt;a href="http://pitayan.com"&gt;Pitayan.com&lt;/a&gt; using some popular technologies — &lt;a href="https://gridsome.org"&gt;Gridsome&lt;/a&gt; &amp;amp; &lt;a href="https://netlify.com"&gt;Netlify&lt;/a&gt;. At the beginning, it seems that the blog has a natural attraction that urges me to put more efforts onto it. So I kept writing stories to share my recent studies and projects.&lt;/p&gt;

&lt;p&gt;This little blog is totally a dream come true for me ever since the first time when I came to know about Wordpress back in 2011. The process of creating a blog using Wordpress was so fun that there's not a day without imagining how it will look like after the development is finished. In those years when I was with Wordpress, I've learned a lot about web development. If you are a frontend engineer, I bet you understand the joy and funs of tuning up the designs and program logics for a web app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VP0c2ioX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/5df38c7ed10dbc94c99077f8403f5913/8537d/wordpress.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VP0c2ioX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/5df38c7ed10dbc94c99077f8403f5913/8537d/wordpress.png" alt="images/wordpress.png" title="images/wordpress.png" width="880" height="462"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;images/wordpress.png&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Honestly, that Wordpress blog I made long ago was somehow a "crucial factor" of me quitting my former accounting job and decided to devote myself into software engineering. Now I can feel that it is always what you make out of the imagination brings you the most fantastic memories. So this blog I made today &lt;a href="http://pitayan.com"&gt;Pitayan.com&lt;/a&gt; has become into that indivisible part of my life. I'm loving it!&lt;/p&gt;

&lt;p&gt;However, it's never difficult to admit that the whole blog was created by a whim without any architectural designs. I just simply picked up some of the most cutting-edge technologies: &lt;a href="https://vuejs.org"&gt;Vue.js&lt;/a&gt; / &lt;a href="https://gridsome.org"&gt;Gridsome&lt;/a&gt; / &lt;a href="https://netlify.com"&gt;Netlify&lt;/a&gt;. I also attempted to create a CSS framework &lt;a href="https://rotalacss.com"&gt;Rotala.css&lt;/a&gt; to power up the blog appearance.&lt;/p&gt;

&lt;p&gt;Here is the article of me creating my first ever CSS framework &lt;a href="https://rotalacss.com"&gt;Rotala.css&lt;/a&gt; — &lt;a href="https://pitayan.com/posts/css-framework-attempt/"&gt;Attempting to create a CSS framework&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Believe it or not, all of these "cool looking" features went through a lot of "back and forth" which consumed large amount of my time (I could have done something else much more "engineering"). Well, the final result is just in front of you, it looks elegant minimal and fashionable. Hope you find it enjoyable as well.&lt;/p&gt;

&lt;h1&gt;
  
  
  #The "free" plans
&lt;/h1&gt;

&lt;p&gt;At the time of me writing this article, my blog is hosted on &lt;a href="https://netlify.com"&gt;Netlify&lt;/a&gt; under a free plan. All of the articles are saved in a Github private repository. It's very obvious that I'm taking advantage of "Free of charge".&lt;/p&gt;

&lt;p&gt;But don't take it wrong, the "free" thing here will actually charge you in a different "format" which is clearly written in the service policies and terms.&lt;/p&gt;

&lt;p&gt;And any day in the future, if you hope to continue using the same service but with better functionalities, the "user of inertia" will drive you directly to the port of "subscriptions" or "plans". This is how the nowaday's SaaS business converts their "traffics". (For now, the "free" plan fits me really well thanks to the "open-source spirit" from &lt;a href="https://netlify.com"&gt;Netlify&lt;/a&gt; and &lt;a href="https://github.com"&gt;Github&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;However I really hope the day of upgrading my account could come earlier because it means this blog has gained decent amount of traffic which becomes into a successful site and brings valuable information to the crowd.&lt;/p&gt;

&lt;p&gt;To tell you the truth, maintaining this blog is not totally free of charge. I still have to spend some coins for some extra functions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Domain name on &lt;a href="https://godaddy.com"&gt;Godaddy.com&lt;/a&gt; (20 US dollars a year)&lt;/li&gt;
&lt;li&gt;SEO tool from &lt;a href="https://seranking.com"&gt;SERanking.com&lt;/a&gt; (40 * 12 = 480 US dollars a year) (Btw, I think SEO tool isn't quite a necessary thing at the beginning. I rarely use it to help optimize the article keywords)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The expense in total is 500 US dollars for a year. Yet I made no profit out of it as of today.&lt;/p&gt;

&lt;h1&gt;
  
  
  #The turning point
&lt;/h1&gt;

&lt;p&gt;Most of the tech blogs I've seen on the Internet don't really have ads on it. Maybe they are just blogging for hobbies, thus earnings perhaps don't really matter to them.&lt;/p&gt;

&lt;p&gt;For my part, advertisement is one big reason(target) for me to keep on with it. I consider it as a long-term investment with relatively low cost and high return even this may took much longer than I could imagine.&lt;/p&gt;

&lt;p&gt;But I always confidently believe my blog will eventually become into an "oil field" that's minting dollar bills.&lt;/p&gt;

&lt;p&gt;During 2020's big incident "COVID-19", &lt;a href="https://www.google.com/adsense/start"&gt;Google Adsense&lt;/a&gt; has rejected all of my applications due to the well-known "Review Capacity Reached". This prevented a lot of blog owners to convert their traffic into some real income.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JkssyOml--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/ea998e177e02ff49b43c2ec976595df1/0dafd/adsense_review_capacity_reached.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JkssyOml--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/ea998e177e02ff49b43c2ec976595df1/0dafd/adsense_review_capacity_reached.png" alt="images/adsense_review_capacity_reached.png" title="images/adsense\_review\_capacity\_reached.png" width="880" height="349"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;images/adsense_review_capacity_reached.png&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I’ve also consulted with Adsense community for help. They told me that it's maybe not because &lt;a href="http://pitayan.com"&gt;Pitayan.com&lt;/a&gt; is not eligible but it's just that Google don't really have enough auditing resources for the time being.&lt;/p&gt;

&lt;p&gt;After searching the answers on the community forum, I think I've found the most reliable solution which is to submit the application once a while. And then I started taking my chances clicking that submit button once a month.&lt;/p&gt;

&lt;p&gt;Just around 2 weeks before (May 28th 2021) I started writing this article, my application for &lt;a href="https://www.google.com/adsense/start"&gt;Google Adsense&lt;/a&gt; has been approved! It is such great news to my 2020's effort.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ijkp1xdO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/799d0ef55c86f09ed962754e78a86d38/c0141/adsense_approval.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ijkp1xdO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/799d0ef55c86f09ed962754e78a86d38/c0141/adsense_approval.png" alt="images/adsense_approval.png" title="images/adsense\_approval.png" width="880" height="603"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;images/adsense_approval.png&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hooray 🎉🎉🎉🎉🎉🎉!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I am so excited to be able to put some advertisements to the blog pages. However, after a few days of consideration I've decided not to do it so quickly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;why&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;Well, here are the reasons not to display ads at the moment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The blog isn't a well-thought product. Adding ads onto the page will significantly affect the user experience.&lt;/li&gt;
&lt;li&gt;There's not enough amount of traffic and not enough session time. So the ads conversion ratio will lead to a disappointing result.&lt;/li&gt;
&lt;li&gt;I want to migrate to &lt;a href="http://gatsbyjs.com"&gt;Gatsby&lt;/a&gt; for a bigger community. The &lt;a href="https://gridsome.org"&gt;Gridsome&lt;/a&gt; is good enough but the reason why I chose &lt;a href="https://gridsome.org"&gt;Gridsome&lt;/a&gt; at the beginning is that I wanted to learn more about &lt;a href="https://vuejs.org"&gt;Vue.js&lt;/a&gt;. Now it's time to get back to &lt;a href="http://reactjs.org"&gt;React&lt;/a&gt; for my personal flavor. (I'll write an article about why I choose &lt;a href="http://reactjs.org"&gt;React&lt;/a&gt; over &lt;a href="https://vuejs.org"&gt;Vue.js&lt;/a&gt; in the end)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Above all, if I hope to implement Google advertisements I need to remake my blog &lt;a href="http://pitayan.com"&gt;Pitayan.com&lt;/a&gt; first.&lt;/p&gt;

&lt;h1&gt;
  
  
  #The architecture design
&lt;/h1&gt;

&lt;p&gt;Once you choose to go with static site generators like &lt;a href="http://gatsbyjs.com"&gt;Gatsby&lt;/a&gt; or &lt;a href="https://gridsome.org"&gt;Gridsome&lt;/a&gt;, the rest of the things to do is to start writing and then deploy the articles to &lt;a href="https://netlify.com"&gt;Netlify&lt;/a&gt; with their pre-configured starter template. Everything is so "open-box" that you don't quite need to modify a lot of things by yourself.&lt;/p&gt;

&lt;p&gt;However this time, I hope to bring some solid engineering practices to make it robust and foreseeable. It'd be very hard to picture every single detail for each of the features. So, it's perhaps a good idea to just initialize a rather intuitive features outline in the first place. And then, I'll drill down to each of them to fill in the missing details.&lt;/p&gt;

&lt;h2&gt;
  
  
  #Features outline
&lt;/h2&gt;

&lt;p&gt;The following items are those essential components to take into consideration. You can call it "minimal requirements".&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Github repo 1: Source code&lt;/li&gt;
&lt;li&gt;Github repo 2: UI&lt;/li&gt;
&lt;li&gt;Github repo 3 (private repo): Posts&lt;/li&gt;
&lt;li&gt;Tests&lt;/li&gt;
&lt;li&gt;Github Actions (CI/CD)&lt;/li&gt;
&lt;li&gt;Netlify setup&lt;/li&gt;
&lt;li&gt;Google Tag manager

&lt;ul&gt;
&lt;li&gt;Google Analytics&lt;/li&gt;
&lt;li&gt;Google Adsense&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  #Github repos
&lt;/h2&gt;

&lt;p&gt;There will be 3 major Github repos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Repo 1 (Source code)&lt;/strong&gt;: The main repository that follows the Gatsby folder structure. &lt;a href="https://netlify.com"&gt;Netlify&lt;/a&gt; will use this repo for builds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repo 2 (UI)&lt;/strong&gt;: It contains all of the necessary UI components for a blog. And also showcase the collection of components to public under a subdomain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repo 3 (Posts)&lt;/strong&gt;: It contains all of the blog articles.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the 3 repos have a simple relationship among them:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0FgIu9jK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/3dd345495125053b55c846cadb8cc43f/b1680/repo_relationship.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0FgIu9jK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/3dd345495125053b55c846cadb8cc43f/b1680/repo_relationship.png" alt="images/repo_relationship.png" title="images/repo\_relationship.png" width="880" height="574"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;images/repo_relationship.png&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Repo 3 is a Git submodule of Repo 1. Repo 2 is a JS package dependency of Repo 1.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  #Tests
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KfjIQIVb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/bbc0e4e50254b32c3c95ec0c77a65e31/e9504/tests.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KfjIQIVb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/bbc0e4e50254b32c3c95ec0c77a65e31/e9504/tests.png" alt="images/tests.png" title="images/tests.png" width="809" height="776"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;images/tests.png&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Repo 1 (Source code) &amp;amp; Repo 2 (UI) will have unit tests and e2e tests.&lt;/p&gt;

&lt;p&gt;Repo 3 (Posts) has no tests since it's only used as a "database".&lt;/p&gt;

&lt;h2&gt;
  
  
  #Github Actions (CI/CD)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  #Repo 1 (Source code) &amp;amp; Repo 2 (UI)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Detect PR, run tests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(As a personal project, it feels quite redundant to create a PR and merge it by myself... And I'm quite used to merge the changes directly and push them to the remote repo. But I think this disobeys the "engineering spirit" 🤓, right?)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rQQWjrRs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/d55bb59d9142f97148a131cb27009402/0d6a1/repo_1_actions.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rQQWjrRs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/d55bb59d9142f97148a131cb27009402/0d6a1/repo_1_actions.png" alt="images/repo_1_actions.png" title="images/repo\_1\_actions.png" width="588" height="347"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;images/repo_1_actions.png&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  #Repo 3 (Posts)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Detect PR, automatically merge to develop if test passed (Same to Repo 1)&lt;/li&gt;
&lt;li&gt;Weekly Crontab, automatically merge develop to master if test passed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both of the CI jobs will finally trigger &lt;a href="https://netlify.com"&gt;Netlify&lt;/a&gt; to build the source.&lt;/p&gt;

&lt;p&gt;Note that Repo 3 (Posts) has no tests. The CI job has to collaborate with Repo 1 (Source code). The test here behaves like a logic switch to guard against anything wrong with Repo 1 (Source code) so that it won't proceed to "merge" or "build" step when test cases failed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vSjwyapa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/a7eea8475a5e14c070887e0964f7dca8/a6927/repo_3_actions.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vSjwyapa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/a7eea8475a5e14c070887e0964f7dca8/a6927/repo_3_actions.png" alt="images/repo_3_actions.png" title="images/repo\_3\_actions.png" width="880" height="485"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;images/repo_3_actions.png&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  #Netlify
&lt;/h2&gt;

&lt;p&gt;In the new architecture design, most of the settings on &lt;a href="https://netlify.com"&gt;Netlify&lt;/a&gt; will probably stay unchanged.&lt;/p&gt;

&lt;p&gt;Apart from the current "build &amp;amp; deploy" workflow, there are some "boost-up" features I want to add to &lt;a href="https://netlify.com"&gt;Netlify&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trigger &lt;strong&gt;preview build&lt;/strong&gt; on develop branch (like a staging environment)&lt;/li&gt;
&lt;li&gt;Trigger &lt;strong&gt;production build&lt;/strong&gt; on master branch&lt;/li&gt;
&lt;li&gt;Notify subscribers (Email &amp;amp; SNS) on a successful &lt;strong&gt;production build&lt;/strong&gt; for the new post &lt;code&gt;tentative&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gopcFlA2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/f704cb721f2f637248c51c4fcbb5c003/2083b/netlify_builds.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gopcFlA2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/f704cb721f2f637248c51c4fcbb5c003/2083b/netlify_builds.png" alt="images/netlify_builds.png" title="images/netlify\_builds.png" width="880" height="797"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;images/netlify_builds.png&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://netlify.com"&gt;Netlify&lt;/a&gt; provides this "Branch subdomain" function to allow deploying a branch to a sub-domain. Which will be used as a staging environment for me to confirm the changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5eCfIvBQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/a456da9882d2e22ece8ab2fc7c58b04e/c533c/netlify_branch_subdomains.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5eCfIvBQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/a456da9882d2e22ece8ab2fc7c58b04e/c533c/netlify_branch_subdomains.png" alt="images/netlify_branch_subdomains.png" title="images/netlify\_branch\_subdomains.png" width="880" height="230"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;images/netlify_branch_subdomains.png&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Notifying subscribers will be a very important automation feature. Usually I'll send out my new article manually to SNS subscribers after the deployment. (Unfortunately, there's no email subscribers yet 😐)&lt;/p&gt;

&lt;p&gt;By the way, I did some research on the "post-build notification" thing but found nearly no articles about how we could send out tweets and emails after the deployment. However, there's a "Outgoing Webhook" thing for me to coupe with what's after the deployment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Kas6fa6l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/4e140b020bc09275f4545734ec905c82/46649/netlify_outgoing_notifications.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Kas6fa6l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/4e140b020bc09275f4545734ec905c82/46649/netlify_outgoing_notifications.png" alt="images/netlify_outgoing_notifications.png" title="images/netlify\_outgoing\_notifications.png" width="880" height="486"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;images/netlify_outgoing_notifications.png&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Anyway, this feature may consume a lot of time throughout development and researches. Let me mark it as tentative.&lt;/p&gt;

&lt;h2&gt;
  
  
  #Google Tag Manager
&lt;/h2&gt;

&lt;p&gt;Now &lt;a href="http://pitayan.com"&gt;Pitayan.com&lt;/a&gt; has installed Google Analytics tags for counting page views. The implementation is together with source code. I kinda regretted not implementing the tags with Tag Manager when I noticed how powerful it is now.&lt;/p&gt;

&lt;p&gt;With Tag Manager, the Adsense can be installed easily without any coding in the source repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  #Put them all together
&lt;/h2&gt;

&lt;p&gt;I've created a rough workflow digram to make everything intuitive and also relational. It now looks like a vivid system when put together.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fBe2aAs6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/5f4a701ee2d1fa29d148890fe8406dfb/a089c/Pitayan_new_architecture.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fBe2aAs6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pitayan.com/static/5f4a701ee2d1fa29d148890fe8406dfb/a089c/Pitayan_new_architecture.png" alt="images/Pitayan_new_architecture.png" title="images/Pitayan\_new\_architecture.png" width="880" height="428"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;images/Pitayan_new_architecture.png&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  #Lastly
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;Is all of this worth it? It's just a blog.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yes. I'm taking a great pain to make all aspects of a blog under control. Anyway, it's also a good opportunity to practice designing a system even though everything here seems making a mountain out of a molehill. So, in my opinion this is exactly what "engineering" looks like. It visualizes the "known" and "unknown" parts clearly and helps understand how we should approach the solutions.&lt;/p&gt;

&lt;p&gt;There are a lot more to do including task management and integrations etc. I'll move on to list out all of the necessary tasks for the next step which will be written as a different article &lt;a href="https://dev.to/posts/remake-pitayan-blog-part-2"&gt;Remake Pitayan Blog (part 2)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Can't wait to write some code and have fun with it!!&lt;/p&gt;

</description>
      <category>systemdesign</category>
    </item>
    <item>
      <title>A petty trick in front of a builtin function</title>
      <dc:creator>Yanze Dai</dc:creator>
      <pubDate>Tue, 19 Jan 2021 00:00:00 +0000</pubDate>
      <link>https://dev.to/pitayan/a-petty-trick-in-front-of-a-builtin-function-1a2e</link>
      <guid>https://dev.to/pitayan/a-petty-trick-in-front-of-a-builtin-function-1a2e</guid>
      <description>&lt;p&gt;Originally published on &lt;a href="https://pitayan.com/posts/petty-trick-in-front-of-a-builtin-function"&gt;Pitayan | A petty trick in front of a builtin function&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lately, I was working on a project that’ll heavily concentrating on the server-side. Although those server-side stuffs aren’t really my expertise. The lucky part is that this project is about process the HTTP header and return a proper json as response.&lt;/p&gt;

&lt;p&gt;After most of my challenges are completed, there’s one last problem for me to solve:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“How do I get only the domain name and extension name out of a host name?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For instance, you’ve got some string domains as input:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;www.google.com
www.google.co.jp
mail.google.com.hk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The expected output should be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;google.com
google.co.jp
google.com.hk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After some research, I came to know that there’s a builtin function &lt;code&gt;gethostbyname&lt;/code&gt; from a native C library &lt;code&gt;netdb&lt;/code&gt; which can be directly adopted into my program. The function is well explained in the &lt;a href="https://www.gnu.org/software/libc/manual/html_node/Host-Names.html"&gt;https://www.gnu.org/software/libc/manual/html_node/Host-Names.html&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Just take a look at the solution out there, it’s easily parsing the hostname into a easy-to-use data structure which completely is the final answer to look for.&lt;/p&gt;

&lt;p&gt;Actually, before I investigated this builtin function, I’ve got myself another solution. And here is what I thought.&lt;/p&gt;

&lt;h2&gt;
  
  
  #My own approach
&lt;/h2&gt;

&lt;p&gt;Just by taking look at the input and output. It’s obviously an easy problem of processing strings. The first idea I came up with was cutting the first group of strings and return the rest of them.&lt;/p&gt;

&lt;p&gt;My idea was obviously naive after running a couple of tests. Because some scenarios like multiple sub-domains weren’t taken into consideration.&lt;/p&gt;

&lt;p&gt;For instance, a host name like this one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;one.two.abc.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;abc.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If I only cut the first group of strings. The result is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;two.abc.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s still far from the correct answer. Then I realized that such “obviously easy” algorithm problem shouldn’t be solved by a brute force. There must be a certain pattern in it.&lt;/p&gt;

&lt;p&gt;My ration told me to list all of the elements from the hostnames and then find out some aspects to brainstorm with later.&lt;/p&gt;

&lt;p&gt;Alright. What does a hostname consist of?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Domain name + Delimiter + Extension name&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For &lt;code&gt;google.com&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;google as domain name&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.&lt;/code&gt; as delimiter&lt;/li&gt;
&lt;li&gt;com as extension name&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Okay. I think I’ve found something here...&lt;/p&gt;

&lt;p&gt;There’s actually a simple formula to balance the numbers of delimiters and sectors&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;delimiters = sectors - 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usually the extension is either 1 sector (.com) or 2 sectors (co.cc). So if I could enumerate all of the 2-sector extensions, then the domain name is apparently an easy catch.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;It is quite common to say that species of the 2-sector extensions aren’t many. Most of such extensions starts with either “co” or “com”. For instance, co.jp &amp;amp; com.hk.&lt;/p&gt;

&lt;p&gt;So in all, the solution would be doing the following things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Split the hostname by delimiter of “.”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check if the second to last element is “co” or “com”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;if &lt;code&gt;yes&lt;/code&gt;, then take the third to last element as domain name.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;if &lt;code&gt;no&lt;/code&gt;, then take the second to last element as domain name.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  #Implementation
&lt;/h2&gt;

&lt;p&gt;Here is my implementation in C:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function getdomainbyhost(char *http_host)
{
  char *res = calloc(128, sizeof(char));

  // return directly if Dev env
  if (!strcmp(http_host, "localhost") ||
      !strcmp(http_host, "127.0.0.1") ||
      !strcmp(http_host, "0.0.0.0"))
  {
    sprintf(res, "%s", http_host);

    return res;
  }
  // Get "." occurrence frequency in host
  // e.g. a.b.google.com.hk =&amp;gt; 4
  // e.g. b.google.com.hk =&amp;gt; 3
  // e.g. google.co.jp =&amp;gt; 2
  // e.g. google.com.hk =&amp;gt; 2
  // e.g. google.com =&amp;gt; 1
  int occur = 0;
  for (int i = 0; http_host[i] != '\0'; ++i)
  {
    if (http_host[i] == '.')
    {
      ++occur;
    }
  }

  if (occur == 1)
  {
    sprintf(res, "%s", http_host);

    return res;
  }

  char *arr[32];
  int i = 0;
  char domain_name[128];
  memcpy(domain_name, http_host, strlen(http_host));
  domain_name[strlen(http_host)] = '\0';
  char *token = strtok(domain_name, ".");

  while (NULL != token)
  {
    arr[i++] = token;
    token = strtok(NULL, ".");
  }

  // If it's 2-worded domain extension, check the second to last word
  // e.g. google.com.hk =&amp;gt; check "com" =&amp;gt; google.com
  // e.g. some-service.google.com =&amp;gt; =&amp;gt; check "google" =&amp;gt; google.com
  regex_t regex_domain_ext;
  regcomp(&amp;amp;regex_domain_ext, REGEX_DOMAIN_EXT, REG_EXTENDED | REG_NOSUB);
  int match_result = regexec(&amp;amp;regex_domain_ext, arr[occur - 1], 0, NULL, 0);
  regfree(&amp;amp;regex_domain_ext);

  if (match_result != REG_NOMATCH)
  {
    sprintf(res, "%s.%s.%s", arr[occur - 2], arr[occur - 1], arr[occur]);
  }
  else
  {
    sprintf(res, "%s.%s", arr[occur - 1], arr[occur]);
  }

  return res;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s perhaps never a good solution. And it may look a bit buggy and will not pass some of the QA tests. Just as you know, I'll have to use the builtin function &lt;code&gt;gethostbyname&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But I believe it's a good practice of solving problems in an unique way. Maybe in the feature days when I take a look back on what I’ve done here, I’ll think myself a super idiot coming out with such dumb solution.&lt;/p&gt;

</description>
      <category>algorithms</category>
    </item>
    <item>
      <title>Making a modern JS library in 2020</title>
      <dc:creator>Yanze Dai</dc:creator>
      <pubDate>Thu, 05 Nov 2020 13:59:20 +0000</pubDate>
      <link>https://dev.to/pitayan/making-a-modern-js-library-in-2020-2e70</link>
      <guid>https://dev.to/pitayan/making-a-modern-js-library-in-2020-2e70</guid>
      <description>&lt;p&gt;Originally published on &lt;a href="https://pitayan.com/posts/modernest-lib-hello-world/?ref=dev.to"&gt;Pitayan.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recently, I was assigned a task of creating a new JS library to replace the obsolete one that's been released for almost 8 years. This is a quite intruiging task because I'm also permitted to try everything new to make this project much more robust. The first thing came to my mind was to have myself a complex but great "development environment" which explains exactly properly vividly why I'm a DX first developer :D. In this article, I'll demonstrate how I made it with a little "hello-world" repo.&lt;/p&gt;

&lt;p&gt;Why the fuss? Is it worth?&lt;/p&gt;

&lt;p&gt;Suppose you are in a war, the battalion chief only gives you the bayonet to battle with the enemies. Do you think you dare to charge forward while your enemies are using machine guns? I bet 99% of us are not brave enough to do so (Please don't tell me you'd like to die for glory).&lt;/p&gt;

&lt;p&gt;So what if the battalion cheif gives you the most lethal weapon that can defeat your enemies with only one click just like Thanos' snap of fingers? I guess now you got the courage to fight against the enemies :P.&lt;/p&gt;

&lt;p&gt;Anyway, I'd like to become that battalion chief providing lethal weapons to my teammates in order to remove the painful part from our development. When our development has become into a joyful experience, I believe the fuss of moving things back and forth is definitely worth of it.&lt;/p&gt;

&lt;p&gt;Okay, here is the link to my demo repo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/daiyanze/modern-hello-world"&gt;https://github.com/daiyanze/modern-hello-world&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Inspiration
&lt;/h2&gt;

&lt;p&gt;For making our great new library a real modern one, I've been doing some research on varieties of modern JS repos.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Angular&lt;/li&gt;
&lt;li&gt;Vue-next&lt;/li&gt;
&lt;li&gt;Graphql-js&lt;/li&gt;
&lt;li&gt;popper-js&lt;/li&gt;
&lt;li&gt;next.js&lt;/li&gt;
&lt;li&gt;redux&lt;/li&gt;
&lt;li&gt;and some other interesting libraries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I found that all of these libraries have one thing in common:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;They all happen to conincide having either Jest or Mocha/Chai as their testing suites.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Actually Jest and Mocha/Chai have been in the market for years, they are pretty solid. Even there are some new comers like Ava.js, but they still cannot replace the ones with larger community at the momment.&lt;/p&gt;

&lt;p&gt;It's already quite a common sense to choose the libraies with larger communities. Because their code is being tested by many other people, and have more bug fixes. In one word: Almost no one is brave enough to use those librarie that are not being tested thoroughly.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How to know if a library has a large community?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Simple, just check if they have many Github stars or issues. "Stars" usually means the library is pretty qualified and accepted by developers. "Issues" in some degree refects the community interactivity and library activeness. Those 2 indicators should be very reliable for our technology selection.&lt;/p&gt;

&lt;p&gt;Therefore, I will choose those tools as our devDependencies from Github that have lots of stars and issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dependency Features
&lt;/h2&gt;

&lt;p&gt;Here are some of the mayjor ("must") features for our new project. In my opinion, these features have somewhat been the technology selection standard for a new JS library to start up with in 2020.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Typescript
&lt;/h3&gt;

&lt;p&gt;Writing code without types was actually a pain in the ass, "TypeError" will surely appear if we don't think of our data type in advance. So nowadays, since Typescript has become into quite a standard or convention of almost all of the new born JS libraries. Without a doubt, this feature is a "must" to our project.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Jest
&lt;/h3&gt;

&lt;p&gt;Test is another thing that a JS project cannot live without. I believe not a team leader will choose a technology that's not even being tested by itself. So Jest is certainly the utility that we need for tests, as you know they got a big community.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Prettier
&lt;/h3&gt;

&lt;p&gt;Unifying the team's coding style is time-saving. It matters the most when you are visiting your teammates pull request.&lt;/p&gt;

&lt;p&gt;The first time when I saw this tool was 2017. Back then, there was almost no JS code formatters in the open market. Well, Prettier made it available. You can format the code the way you hope it should look like.&lt;/p&gt;

&lt;p&gt;And what's more, with the help of ESlinter or TSlinter the editor could become into a really cool stuff for JS developers.&lt;/p&gt;

&lt;p&gt;The reason to adopt such tools is simple because:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;They give you hints!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Just take a look at the &lt;a href="https://github.com/airbnb/javascript"&gt;Airbnb's javascript style guide&lt;/a&gt; which was created 7 years ago, you'll know how important the code style is.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Husky &amp;amp; Conventional-changelog
&lt;/h3&gt;

&lt;p&gt;I think everyone has the following insatiable wishes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I wish my project can spit out the changelog automatically.&lt;br&gt;
I wish the commit format can be united.&lt;br&gt;
I wish ...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;These tools may sound stange to you. But they are actually a great combination to generate stable changelogs automatically based on the git commit messages. Angular project is using this approach to create better changelogs.&lt;/p&gt;

&lt;p&gt;Take a look at the Angular's beatiful changelog:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;11.0.0-next.3 (2020-09-23)

Bug Fixes

common: add params and reportProgress options to HttpClient.put() overload (#37873) (dd8d8c8), closes #23600
compiler-cli: generate let statements in ES2015+ mode (#38775) (123bff7)
core: ensure TestBed is not instantiated before override provider (#38717) (c8f056b)
forms: type NG_VALUE_ACCESSOR injection token as array (#29723) (2b1b718), closes #29351
Features

common: Add ISO week-numbering year formats support to formatDate (#38828) (984ed39)
compiler: Parse and recover on incomplete opening HTML tags (#38681) (6ae3b68), closes #38596
router: add migration to update calls to navigateByUrl and createUrlTree with invalid parameters (#38825) (7849fdd), closes #38227
service-worker: add the option to prefer network for navigation requests (#38565) (a206852), closes #38194
BREAKING CHANGES

core: If you call TestBed.overrideProvider after TestBed initialization, provider overrides are not applied. This behavior is consistent with other override methods (such as TestBed.overrideDirective, etc) but they throw an error to indicate that, when the check was missing in the TestBed.overrideProvider function. Now calling TestBed.overrideProvider after TestBed initialization also triggers an error, thus there is a chance that some tests (where TestBed.overrideProvider is called after TestBed initialization) will start to fail and require updates to move TestBed.overrideProvider calls before TestBed initialization is completed.

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Just don't write the changelog yourself. Let the machines handle them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Okay, these 4 tools are basically the features I'm really really eager for as a "DX-first" developer. There are of course some other nice features to have, but I think it's already enough to start with at the moment. After all, new more tools will increase the learning time for each of our members.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "Rollup"
&lt;/h2&gt;

&lt;p&gt;While I was prototyping my repository, I never thought that Rollup would be the biggest challenge to me. Rollup has a great document which you would understand what it hopes you to do immediately just by looking at the examples. But the true problems locate at how I should handle my output files.&lt;/p&gt;

&lt;p&gt;Since my output is a library, I need to rollup all my sources into one JS file that can be used within a browser (or maybe Node.js). This can be easily done by Gulp or Grunt with some plugins. I'm pretty new to this magical tool that has enpowered the most famous frameworks like Vue and React.&lt;/p&gt;

&lt;p&gt;Frankly speaking, I don't know much about how I should move next.&lt;/p&gt;

&lt;p&gt;In order to save those steps of moving back and forth, I gave up on exploring the Rollup configurations. As you could imagine, there's no way for a "noob" to create something "great" from completely zero.&lt;/p&gt;

&lt;p&gt;Alright, then. Let me try another approach.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If I don't know how to do it, then somebody else should know.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Vue and React have already done the homework, the rest is me copying them :D.&lt;br&gt;
(Very proud of being a copycat~)&lt;/p&gt;

&lt;p&gt;I chose &lt;a href="https://github.com/vuejs/vue-next"&gt;Vue 3.0&lt;/a&gt; to be my targeted repo because it's quite a new project. And Vue currently has a very high popularity.&lt;/p&gt;

&lt;p&gt;Its configuration is a bit complex, but still very easy to understand.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Part of rollup.config.js in Vue-next repo&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ts&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rollup-plugin-typescript2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;replace&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@rollup/plugin-replace&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@rollup/plugin-json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TARGET&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TARGET package must be specified via --environment flag.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;masterVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./package.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;packagesDir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;packages&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;packageDir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;packagesDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TARGET&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;packageDir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;packageDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pkg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`package.json`&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;packageOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pkg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buildOptions&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="c1"&gt;// ensure TS checks only once for each build&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;hasTSChecked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;outputConfigs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;esm-bundler&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`dist/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.esm-bundler.js`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`es`&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;After exploring the &lt;a href="https://github.com/vuejs/vue-next"&gt;Vue 3.0&lt;/a&gt; configuration file &lt;code&gt;rollup.config.js&lt;/code&gt;, I found that it only does 3 things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;receive the command line parameters via another script&lt;/li&gt;
&lt;li&gt;generate list of configs for different types of builds&lt;/li&gt;
&lt;li&gt;export that configs list&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just by doing a bit of copy &amp;amp; pasting, I managed to create a custom Rollup configuration file that has the above features. But I replaced one of the Rollup plugins because I personally favor the official packages.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Changed &lt;code&gt;rollup-plugin-typescript&lt;/code&gt; to the official &lt;code&gt;@rollup/plugin-typescript&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vue provides various types of builds which I think is a smart move, because the users will have different development purposes and environment.&lt;/p&gt;

&lt;p&gt;For now, we could see that Vue offers the following types of build outputs based on the output format of JS code (&lt;code&gt;es&lt;/code&gt; &amp;amp; &lt;code&gt;cjs&lt;/code&gt; &amp;amp; &lt;code&gt;iife&lt;/code&gt;). The ones with a &lt;code&gt;prod&lt;/code&gt; in the file name is used for production purposes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Vue dist&lt;/span&gt;

vue.cjs.js
vue.cjs.prod.js
vue.d.ts
vue.esm-browser.js
vue.esm-browser.prod.js
vue.esm-bundler.js
vue.global.js
vue.global.prod.js
vue.runtime.esm-browser.js
vue.runtime.esm-browser.prod.js
vue.runtime.esm-bundler.js
vue.runtime.global.js
vue.runtime.global.prod.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hope that this approach can be applied in our project. Similarly but differently, the build outputs with a &lt;code&gt;dev&lt;/code&gt; in the file name is the ones for development.&lt;/p&gt;

&lt;p&gt;And what's more, we don't really separate the builds like Vue by judging if it's the &lt;code&gt;runtime&lt;/code&gt; or not. So the following outputs are the final targets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# hellowrold dist&lt;/span&gt;

helloworld.cjs.js &lt;span class="c"&gt;# for using our library via `require` method&lt;/span&gt;
helloworld.cjs.dev.js
helloworld.d.ts
helloworld.esm.js &lt;span class="c"&gt;# for using our library via `import` keyword&lt;/span&gt;
helloworld.esm.dev.js
helloworld.js &lt;span class="c"&gt;# for browser&lt;/span&gt;
helloworld.dev.js
helloworld.modern.js &lt;span class="c"&gt;# for modern browser like latest Chrome or latest Firefox&lt;/span&gt;
helloworld.modern.dev.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the link to the &lt;code&gt;rollup.config.js&lt;/code&gt;: &lt;a href="https://github.com/daiyanze/modern-hello-world/blob/master/rollup.config.js"&gt;modern-hello-wrold rollup config&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;TLDR;&lt;/code&gt;... but be patient :P.&lt;/p&gt;

&lt;h3&gt;
  
  
  some issues of my rollup configuration
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Type checking issue
&lt;/h4&gt;

&lt;p&gt;It seems that even if I hope to build only one package at a time, the Typescript is checking all of the packages within the monorepo no matter they are dependencies to the build target or not.&lt;/p&gt;

&lt;p&gt;Besides, the type checking is likely to happen many times while building multiple packages. I could hear my fan is pretty busy during builds. (This is pretty unnecessary)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/vuejs/vue-next"&gt;Vue 3.0&lt;/a&gt; repo used a flag to disable the duplicated type checking while I didn't. I'm not very sure if this is a good approach or not. But it will surely affect our development or even production builds.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Declaration exports issue
&lt;/h4&gt;

&lt;p&gt;My helloworld is using the same tool (API-Extractor) and configurations of Vue for extracting the type declarations from the source code. I'm using a different Typescript plugin. Regrading building declaration outputs, I need to pass the &lt;code&gt;tsconfig.json&lt;/code&gt; parameter &lt;code&gt;declaration&lt;/code&gt; to that plugin.&lt;/p&gt;

&lt;p&gt;Apparently, I didn't do it. Because I opinionatedly thought building without &lt;code&gt;declaration&lt;/code&gt; would be slightly faster. And this could be a wrong idea. Anyhow, I should optimize this part later.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "Build" scripts
&lt;/h2&gt;

&lt;p&gt;I think Vue project is quite smart in the "build" process. They use commands directly together with &lt;a href="https://github.com/sindresorhus/execa"&gt;execa&lt;/a&gt; to avoid using the programmable APIs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;execa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rollup&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-wc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--environment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="s2"&gt;`NODE_ENV:development`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;stdio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;inherit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/sindresorhus/execa"&gt;execa&lt;/a&gt; gives us the direct experience of using those farmiliar commands just by regroup the fragments together. This made things a lot simpler IMHO.&lt;/p&gt;

&lt;p&gt;I was once thinking about using the Rollup APIs to handle the builds. But after taking a look at the official document, I realised that it is a stupid idea. It made me feel like enforcing a newbie guitar player who can only play 3 chords to beat the rythm in a big concert.&lt;/p&gt;

&lt;p&gt;In a brief conclusion: sometimes it's maybe a good idea to comprimise to ones making things simpler.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "packages"
&lt;/h2&gt;

&lt;p&gt;As I hope to make it a "Monorepo", the &lt;code&gt;packages/&lt;/code&gt; folder contains all of the necessary builtin modules.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In the demo repo, we have 2 modules in total&lt;/span&gt;
packages/
  helloworld/
    src/
      index.ts
    index.js
    package.json
  shared/
    src/
      print.ts
    index.js
    package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;shared&lt;/code&gt; module is like a &lt;strong&gt;helper&lt;/strong&gt; or &lt;strong&gt;util&lt;/strong&gt; in a normal repo, but it's used as a package so that I could import it as if I'm using a third party lib.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;print&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@helloworld/shared&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;helloWorld&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__DEV__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;It's under development&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello world&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I personally favor the naming convention of prefixing an &lt;code&gt;@&amp;lt;global_module_name&amp;gt;&lt;/code&gt; to the package. This made all of my modules look very united.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@helloworld/shared"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I found out that &lt;a href="https://github.com/vuejs/vue-next"&gt;Vue 3.0&lt;/a&gt; repo uses &lt;code&gt;NODE_ENV&lt;/code&gt; to define the target commonjs module (because the &lt;code&gt;require&lt;/code&gt; context usually ignores the Node environment). It will help the users to include the correct script accordingly.&lt;/p&gt;

&lt;p&gt;Inside the root dir of each module, I copied &amp;amp; pasted how &lt;a href="https://github.com/vuejs/vue-next"&gt;Vue 3.0&lt;/a&gt; handles its commonjs modules by adding a new entry file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// packages/helloworld/index.js&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use strict&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./dist/helloworld.cjs.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./dist/helloworld.cjs.dev.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference between &lt;code&gt;helloworld.cjs.js&lt;/code&gt; and &lt;code&gt;helloworld.cjs.dev.js&lt;/code&gt; in my example is whether it contains the following code block which only serves the script for development. (Have to say that Rollup "treeshaking" is quite an eye opener to me)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="c1"&gt;// "if (__DEV__)" is treeshaked by Rollup&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;It&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="s1"&gt;s under development&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The "summary"
&lt;/h2&gt;

&lt;p&gt;During these several weeks of investigation over the &lt;a href="https://github.com/vuejs/vue-next"&gt;Vue 3.0&lt;/a&gt; repository, I think I've found enough fresh new stuffs to learn about. My recent task won't get kicked-off easily without those smart ideas from them.&lt;/p&gt;

&lt;p&gt;Now my project was succesfully released. When I saw my teammates having fun with the "well-thought repository", I feel my effort is really worth it.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Attempting to create a CSS framework</title>
      <dc:creator>Yanze Dai</dc:creator>
      <pubDate>Wed, 19 Aug 2020 09:48:21 +0000</pubDate>
      <link>https://dev.to/pitayan/attemping-to-create-a-css-framework-5908</link>
      <guid>https://dev.to/pitayan/attemping-to-create-a-css-framework-5908</guid>
      <description>&lt;p&gt;In 2019, I created a CSS framework and named it &lt;a href="https://rotalacss.com?ref=pitayan"&gt;Rotala.css&lt;/a&gt;. After some refactorings and modifications, I finally released the "toy" framework in 2020. But still it is under prototyping because I think my solution is not yet elegant.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visit &lt;a href="https://pitayan.com/posts/css-framework-attempt/?ref=dev.to"&gt;Pitayan.com&lt;/a&gt; to read the original article.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Beginning
&lt;/h2&gt;

&lt;p&gt;The reason why I built this framework is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I want a css framework myself&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I knew it will cost me a lot of time to start building it from scratch. So I hope to create such framework by standing on the shoulder of some other powerful tools in order to speed up my development.&lt;/p&gt;

&lt;p&gt;At first, I started prototyping with &lt;code&gt;SASS&lt;/code&gt;. It is a tool that allows you to combine a lot of unique grammars so that you could experience designing with CSS like programming.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@mixin&lt;/span&gt; &lt;span class="nf"&gt;button-icon&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nd"&gt;button-icon&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Frankly speaking, I learned a lot of good techniques from other famous frameworks like &lt;code&gt;Bootstrap&lt;/code&gt; &amp;amp; &lt;code&gt;Bulma&lt;/code&gt; &amp;amp; &lt;code&gt;Spectre&lt;/code&gt; &amp;amp; &lt;code&gt;Miligram&lt;/code&gt;. And I borrowed some good designs from them especially from &lt;code&gt;Spectre.css&lt;/code&gt; (There's no shame about reinventing the wheels by imitating others).&lt;/p&gt;

&lt;h2&gt;
  
  
  A Remake Attempt
&lt;/h2&gt;

&lt;p&gt;CSS was never my expertise. So I didn't expect any goodies from my initial prototyping. Everything I made the first time was frigile and "copy-cat". There's no "I-created-it" in the framework.&lt;/p&gt;

&lt;p&gt;Even it was just an unexperienced attempt, how could I undertake such bad result?&lt;/p&gt;

&lt;p&gt;Without a doubt, I started it over.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This time, I'll make a great one. Great enough to make me smile.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By a lucky chance, I saw a video talking about a different CSS framework &lt;code&gt;Tailwind.css&lt;/code&gt; which made everything nicer. It is perhaps the time to give it a go.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZVeUjAqa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uopu04dmktgml6jr6jvm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZVeUjAqa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uopu04dmktgml6jr6jvm.png" alt="tailwind.css" width="880" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Tailwind.css&lt;/code&gt; allows you to build your own framework with their "partical" styling classes. I'm quite into such solution since it is the original usage of styling HTML templates.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mx-4 p-2 text-gray-600 bg-gray-300"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;button&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything in &lt;code&gt;Tailwind.css&lt;/code&gt; is segmented tiny enough so that writing these classes into the element is just like putting the building blocks together.&lt;/p&gt;

&lt;p&gt;However, my &lt;a href="https://rotalacss.com?ref=pitayan"&gt;Rotala.css&lt;/a&gt; will output stylesheets not templates. So it is a "must" to figure out how I could make it spit out some files on build.&lt;/p&gt;

&lt;p&gt;The research proved my worry was redundant. All of the styles in &lt;code&gt;Tailwind.css&lt;/code&gt; can be compiled into a small &lt;code&gt;css&lt;/code&gt; file with proper configurations just like &lt;code&gt;SASS&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* Base */&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s2"&gt;"tailwindcss/base"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s2"&gt;"./base.pcss"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/* Components */&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s2"&gt;"tailwindcss/components"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s2"&gt;"./components.pcss"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compile was made simple with &lt;code&gt;postcss-cli&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;postcss docs/main.pcss &lt;span class="nt"&gt;-o&lt;/span&gt; docs/assets/css/rotala.css
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see from the build command, I completely ditched &lt;code&gt;SASS&lt;/code&gt; and migrated to &lt;code&gt;Postcss&lt;/code&gt;. There's nothing bad about &lt;code&gt;SASS&lt;/code&gt;, but I just hope to stick with only one technology for my framework to avoid some complexities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Construct the Source Folder
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OV1MWlut--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4fcy8jzjsndmvp73mqft.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OV1MWlut--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4fcy8jzjsndmvp73mqft.png" alt="github rotala css repository" width="880" height="218"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Along with restart everything over again and again, I finally found a pattern to keep my code base in a good shape.&lt;/p&gt;

&lt;p&gt;The source folder structure looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rotala/
  docs/
  style/
  CHANGELOG.md
  README.md
  package.json
  postcss.config.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;docs/&lt;/code&gt; folder is meant to hold static files that could help demonstrate the output. This is also an alternative setting for Github pages that could easily help publish static page without an extra route param.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docs/
  assets/
  base/
  components/
  index.html
  main.pcss
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;style/&lt;/code&gt; contains all of the source styles. At the beginning, I made around &lt;strong&gt;20&lt;/strong&gt; components because I believe they are quite necessary for building the fundamental parts of a modern website. Those styles were heavily based on &lt;code&gt;Spectre.css&lt;/code&gt; and &lt;code&gt;Bulma&lt;/code&gt; (I'm fan of those frameworks).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;style/
  base/
  components/
    Accordion/
    Typography/
    Badge/
    Breadcrumb/
    Tooltip/
    Button/
    Checkbox/
    Divider/
    Drawer/
    Table Group/
    Form Group/
    Input/
    Tab/
    Avatar/
    Link/
    Menu/
    Modal/
    Notification/
    Pagination/
    Popover/
    Radio/
    Select/
  base.pcss
  components.pcss
  main.pcss
  prefix.pcss
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Making Difference
&lt;/h2&gt;

&lt;p&gt;When you read till this line, you may ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How is it different to other frameworks since you've copied many of their designs?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I do also have the same question in my head. My intention was to create my own CSS framework. Repolishing others' work doesn't smell like a "creating-my-own" spirit. It means this small framework will forever be a toy of mine and has &lt;strong&gt;no value&lt;/strong&gt; to other developers.&lt;/p&gt;

&lt;p&gt;Actually, I also hope someone else could benefit from what I built. But I'm already tired of recreating everything from start. Is there a simple way to bring the dead project back to life by adding some finishing touch?&lt;/p&gt;

&lt;p&gt;Making "different" is truly difficult especially when you don't have any good inspirations.&lt;/p&gt;

&lt;p&gt;What if I take a step back and think about the pros and cons toward &lt;code&gt;Tailwind.css&lt;/code&gt;, could I possbily build up a new feature based on the &lt;code&gt;Tailwind.css&lt;/code&gt;'s legacy and its "shortcomings"? I think the answer would be a "&lt;strong&gt;YES&lt;/strong&gt;".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"md:flex bg-white rounded-lg p-6"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"h-16 w-16 md:h-24 md:w-24 rounded-full mx-auto md:mx-0 md:mr-6"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"avatar.jpg"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-center md:text-left"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-lg"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Erin Lindford&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-purple-500"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Customer Support&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-gray-600"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;erinlindford@example.com&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-gray-600"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;(555) 765-4321&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pros &lt;code&gt;Tailwind.css&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Non-opinionated styles&lt;/li&gt;
&lt;li&gt;Low level utility classes&lt;/li&gt;
&lt;li&gt;Design is customizable&lt;/li&gt;
&lt;li&gt;Plugin system&lt;/li&gt;
&lt;li&gt;Based on &lt;code&gt;Postcss&lt;/code&gt; eco-system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons &lt;code&gt;Tailwind.css&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Template may get too "crowded"&lt;/li&gt;
&lt;li&gt;The file size is "big", need to be purged on build&lt;/li&gt;
&lt;li&gt;Utilities are less semantic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even there are some down sides of &lt;code&gt;Tailwind.css&lt;/code&gt;, I think they can be outweighed by the &lt;code&gt;Pros&lt;/code&gt; far easily. So in my framework, I'll need to figure out plans on dealing with those &lt;code&gt;Cons&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Have to say the 2nd and 3rd &lt;code&gt;Cons&lt;/code&gt; are already part of the &lt;code&gt;Tailwind.css&lt;/code&gt;'s "feauture" which I cannot get rid of. But the first one "crowded template" seems fairly easy to balance with. Thanks to the &lt;code&gt;Tailwind.css&lt;/code&gt;'s powerful function, I could also write my styles in this way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@apply&lt;/span&gt; &lt;span class="nt"&gt;bg-white&lt;/span&gt; &lt;span class="nt"&gt;rounded-lg&lt;/span&gt; &lt;span class="nt"&gt;p-6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;@screen&lt;/span&gt; &lt;span class="nt"&gt;md&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;@apply&lt;/span&gt; &lt;span class="nt"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;I believe the blow usage looks much nicer, isn't it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  ...
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if I hope to change the &lt;code&gt;container&lt;/code&gt; a little bit, I could also use the "template style" to decorate it directly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container font-bold mx-2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  ...
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I clearly understand that I'm not the first one to think in this way, but at least this can be a good feature of my framework to standout among other frameworks.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Core Feature
&lt;/h2&gt;

&lt;p&gt;As I hope to make differences for my framework, I came up with such core feature to accomplish.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Design-less" &amp;amp; "Extensible" components&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First of all, &lt;code&gt;Tailwind.css&lt;/code&gt; is "design-less". It gives full control of the stylings to us developers. I will follow that and make sure all my components are just skeletons that contains very rudimentry styles. By meaning "rudimentry styles", components will have fonts text-size color background-color padding margins et cetera if necessary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nc"&gt;.button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@apply&lt;/span&gt; &lt;span class="nt"&gt;appearance-none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;@apply&lt;/span&gt; &lt;span class="nt"&gt;select-none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;@apply&lt;/span&gt; &lt;span class="nt"&gt;align-middle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;@apply&lt;/span&gt; &lt;span class="nt"&gt;font-medium&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;@apply&lt;/span&gt; &lt;span class="nt"&gt;text-center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;@apply&lt;/span&gt; &lt;span class="nt"&gt;text-base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;@apply&lt;/span&gt; &lt;span class="nt"&gt;no-underline&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;@apply&lt;/span&gt; &lt;span class="nt"&gt;leading-normal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;@apply&lt;/span&gt; &lt;span class="nt"&gt;whitespace-no-wrap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;@apply&lt;/span&gt; &lt;span class="nt"&gt;inline-block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;@apply&lt;/span&gt; &lt;span class="nt"&gt;cursor-pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;@apply&lt;/span&gt; &lt;span class="nt"&gt;rounded-sm&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;@apply&lt;/span&gt; &lt;span class="nt"&gt;py-1&lt;/span&gt; &lt;span class="nt"&gt;px-3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this way, all of the components can be modified into the desired shape just by adding the new styles to override. It follows the original practice of how we should handle the CSS stylings.&lt;/p&gt;

&lt;p&gt;Suppose we are styling the "skeleton button":&lt;/p&gt;

&lt;p&gt;from this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jpmC6Zw8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/9liykdukidb2iq7q9gbs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jpmC6Zw8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/9liykdukidb2iq7q9gbs.png" alt="skeleton button" width="334" height="144"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;to this:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7RVrRucz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jcmhqbpf4mca8dubhthi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7RVrRucz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jcmhqbpf4mca8dubhthi.png" alt="gray button" width="386" height="150"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"button text-gray-700 bg-gray-300 hover:bg-gray-500 transition-colors duration-150"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Background Gray
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a brief expression:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Class + Utilities = Your stylish component&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It may look too crowded in the template. So the better way to use it is maybe to &lt;strong&gt;extend&lt;/strong&gt; the current &lt;code&gt;class&lt;/code&gt; instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nc"&gt;.button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@apply&lt;/span&gt; &lt;span class="nt"&gt;text-gray-700&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;@apply&lt;/span&gt; &lt;span class="nt"&gt;bg-gray-300&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;@apply&lt;/span&gt; &lt;span class="nt"&gt;transition-colors&lt;/span&gt;
  &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nt"&gt;apply&lt;/span&gt; &lt;span class="nt"&gt;duration-150&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;@apply&lt;/span&gt; &lt;span class="nt"&gt;bg-gray-500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;The rest of the tasks will be to implement all other components I hope to have in the framework. It took less time creating each of them than before because I defined how to use the "skeleton" components as a core feature.&lt;/p&gt;

&lt;p&gt;Now there are all essential components for building a website. The blog page you are reading is actually utilizing the &lt;a href="https://rotalacss.com?ref=pitayan"&gt;Rotala.css&lt;/a&gt; framework. There are still a lot of drawbacks but in my opinion it is such an achievement for me to create something I'm not good at from totally 0.&lt;/p&gt;

&lt;p&gt;Anyhow, I'll continue developing the framework. I'd appreciate that you are also interested in my little work here. Feel free to drop me emails to tell about your opinions of &lt;a href="https://rotalacss.com?ref=pitayan"&gt;Rotala.css&lt;/a&gt;. Any PRs or issues are welcome!&lt;/p&gt;

&lt;p&gt;About how to use &lt;a href="https://rotalacss.com?ref=pitayan"&gt;Rotala.css&lt;/a&gt;, refer to the document by clicking the link below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://rotalacss.com?ref=pitayan"&gt;https://rotalacss.com&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Originally on &lt;a href="https://pitayan.com/posts/css-framework-attempt/?ref=dev.to"&gt;Pitayan.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pitayan.com/posts/css-framework-attempt/?ref=dev.to"&gt;https://pitayan.com/posts/css-framework-attempt/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>css</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Vue 3 new features summary</title>
      <dc:creator>Yanze Dai</dc:creator>
      <pubDate>Tue, 11 Aug 2020 12:11:01 +0000</pubDate>
      <link>https://dev.to/pitayan/vue-3-new-features-summary-2cie</link>
      <guid>https://dev.to/pitayan/vue-3-new-features-summary-2cie</guid>
      <description>&lt;p&gt;Vue-next (Vue 3) has been out for a while. It is now under release candidate stage which means there won't be big changes on the open APIs. Good to see that Vue has already been stabilized and ready to waltz into our projects.&lt;/p&gt;

&lt;p&gt;I have to say that Vue 2 is already amazing enough. But with Vue 3's new features, it's likely to upgrade our projects to an upper level. I guess the most thrilling feature in Vue 3 would be the composition APIs. Evan You himself mentioned that the composition APIs are inspired by the React hooks. Even though the two APIs hooks and compositions are a lot alike, but from the code base they are completely different. Let's not discuss which is better or promising because I don't really think either framework outraces another.&lt;/p&gt;

&lt;p&gt;In all, it's so happy to see that Vue can also do what React does. Let's have a close look at the new features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TLDR;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Visit &lt;a href="https://pitayan.com/posts/vue-next-features/?ref=dev.to"&gt;https://pitayan.com/posts/vue-next-features/&lt;/a&gt; to read original article.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Vite
&lt;/h2&gt;

&lt;p&gt;This is another work of art by Evan You which is aim at replacing &lt;a href="https://webpack.js.org"&gt;Webpack&lt;/a&gt; in Vue development (Currently only works for Vue). It is designed to be &lt;strong&gt;fast&lt;/strong&gt; just as its French name implies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting started with Vite
&lt;/h3&gt;

&lt;p&gt;The official repo offers us a simple way to create a Vue 3 app via &lt;a href="https://github.com/vitejs/vite"&gt;Vite&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Npm
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm init vite-app &amp;lt;project-name&amp;gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &amp;lt;project-name&amp;gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Yarn
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;yarn create vite-app &amp;lt;project-name&amp;gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &amp;lt;project-name&amp;gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;yarn
&lt;span class="nv"&gt;$ &lt;/span&gt;yarn dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Start Dev Server
&lt;/h4&gt;

&lt;p&gt;It all happened in a blink of eyes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; ❯ yarn dev
yarn run v1.22.4
&lt;span class="nv"&gt;$ &lt;/span&gt;vite
vite v1.0.0-rc.4

  Dev server running at:
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Local:    http://localhost:3000/
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Network:  http://192.168.3.2:3000/
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Network:  http://10.80.67.216:3000/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;a href="http://localhost:3000/"&gt;http://localhost:3000/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eulZTluf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sz79si8ctbiuoqo5zbvp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eulZTluf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sz79si8ctbiuoqo5zbvp.png" alt="dev page" width="880" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  vue-next-features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/daiyanze/vue-next-features"&gt;repository link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://daiyanze.com/vue-next-features/dist/"&gt;demo link&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I created a small app to &lt;a href="https://daiyanze.com/vue-next-features/dist/"&gt;demo&lt;/a&gt; the new features of Vue 3. If you take a look at the projects' &lt;code&gt;package.json&lt;/code&gt;, the simplicity of &lt;a href="https://github.com/daiyanze/vue-next-features"&gt;vue-next-features&lt;/a&gt; dependencies will make you fond of &lt;a href="https://github.com/vitejs/vite"&gt;Vite&lt;/a&gt; immediately. (I mean, who doesn't want a simpler &lt;code&gt;package.json&lt;/code&gt; to start with?)&lt;/p&gt;

&lt;p&gt;There is another Vue 3 "Hello World" repo (&lt;a href="https://github.com/vuejs/vue-next-webpack-preview"&gt;vue-next-webpack-preview&lt;/a&gt;) bundled with &lt;a href="https://webpack.js.org"&gt;Webpack&lt;/a&gt;. It is also a good playground.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/daiyanze/vue-next-features"&gt;&lt;strong&gt;vue-next-features&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"vite"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^1.0.0-rc.4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"vue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^3.0.0-rc.5"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@vue/compiler-sfc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^3.0.0-rc.5"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/vuejs/vue-next-webpack-preview"&gt;&lt;strong&gt;vue-next-webpack-preview&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"vue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^3.0.0-beta.2"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@vue/compiler-sfc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^3.0.0-beta.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"css-loader"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^3.4.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"file-loader"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^6.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"mini-css-extract-plugin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^0.9.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"url-loader"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"vue-loader"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^16.0.0-alpha.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"webpack"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.42.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"webpack-cli"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^3.3.11"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;¥&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"webpack-dev-server"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^3.10.3"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Composition API
&lt;/h2&gt;

&lt;p&gt;As the biggest the change of &lt;a href="https://vuejs.org"&gt;Vue.js&lt;/a&gt;, the composition API would become your next most frequently and commonly used feature. Just like &lt;a href="https://reactjs.org/docs/hooks-reference.html#"&gt;React hooks&lt;/a&gt;, with the Vue composition API will help gain more customizibilities.&lt;/p&gt;

&lt;p&gt;Here is a list of the Vue 3 composition APIs. (There are actually more...)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Reactivity&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;computed&lt;/code&gt; &lt;code&gt;reactive&lt;/code&gt; &lt;code&gt;ref&lt;/code&gt; &lt;code&gt;readonly&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;watch&lt;/code&gt; &lt;code&gt;watchEffect&lt;/code&gt; &lt;code&gt;unref&lt;/code&gt; &lt;code&gt;toRefs&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;isRef&lt;/code&gt; &lt;code&gt;isProxy&lt;/code&gt; &lt;code&gt;isReactive&lt;/code&gt; &lt;code&gt;isReadonly&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;customRef&lt;/code&gt; &lt;code&gt;markRaw&lt;/code&gt; &lt;code&gt;shallowReactive&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;shallowReadonly&lt;/code&gt; &lt;code&gt;shallowRef&lt;/code&gt; &lt;code&gt;toRaw&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Lifecycle Hooks&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;onBeforeMount&lt;/code&gt; &lt;code&gt;onBeforeUnmount&lt;/code&gt; &lt;code&gt;onBeforeUpdate&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;onMounted&lt;/code&gt; &lt;code&gt;onUpdated&lt;/code&gt; &lt;code&gt;onErrorCaptured&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;onRenderTracked&lt;/code&gt; &lt;code&gt;onRenderTriggered&lt;/code&gt; &lt;code&gt;onUnmounted&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;onActivated&lt;/code&gt; &lt;code&gt;onDeactivated&lt;/code&gt; &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Visit Vue 3 official doc to know more about these APIs.&lt;br&gt;
&lt;a href="https://v3.vuejs.org/api/composition-api.html"&gt;https://v3.vuejs.org/api/composition-api.html&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Component Styles
&lt;/h3&gt;
&lt;h4&gt;
  
  
  In Vue 2
&lt;/h4&gt;

&lt;p&gt;Use configuration template to define the component contents. In Vue 3, this legacy usage is still available. If you'd prefer this style, you can continue using it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"count++"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;count: {{ count }}&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;multiplier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;multiplier&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;mounted&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;oldVal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;oldVal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  In Vue 3
&lt;/h4&gt;

&lt;p&gt;To use the composition API, you'll need to add a &lt;code&gt;setup&lt;/code&gt; property in to the default export. The below code is completely equivalent to the code above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"count++"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;count: {{ count }}&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reactive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;toRefs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onMounted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;watch&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;setup&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;multiplier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;reactive&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;multiplier&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="nx"&gt;onMounted&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="nx"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;oldVal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;oldVal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;toRefs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Go Ahead with the new API
&lt;/h4&gt;

&lt;p&gt;There are 4 reasons why you should use composition API over the default Vue 2 config template:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To increase readability of source code&lt;/li&gt;
&lt;li&gt;To avoid duplicated or redundant logics&lt;/li&gt;
&lt;li&gt;To group up similar logics&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;To reuse the logics&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compared to the Vue 2 configuration style, the logics are precisely broken down into smaller particals so that you could group the similar logics together easily. In this way, it also reduces chances jumping around from irrelavant logics. This will help increase the productivity without a doubt.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Advanced Reactivity API
&lt;/h2&gt;

&lt;p&gt;Personally, I think this is nothing different to the other reactivity APIs. But it indeed offers those abilities of handling edge cases like &lt;strong&gt;custom hooks&lt;/strong&gt; and &lt;strong&gt;shallow layer modification&lt;/strong&gt;. It is now part of the &lt;a href="https://v3.vuejs.org/api/basic-reactivity.html"&gt;basic reactivity API&lt;/a&gt; according to the Vue 3 official doc.&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://composition-api.vuejs.org/"&gt;Vue composition api&lt;/a&gt; doc (Yes, there's a doc only for the composition APIs), the following APIs are listed as &lt;strong&gt;advanced reactivity apis&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;customRef: custom hook&lt;/li&gt;
&lt;li&gt;markRaw: not able to be a &lt;code&gt;reactive&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;shallowReactive: Object's first layer &lt;code&gt;reactive&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;shallowReadonly: Object's first layer &lt;code&gt;readonly&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;shallowRef: Object's value not &lt;code&gt;reactive&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;toRaw: restore a &lt;code&gt;reactive&lt;/code&gt; to normal Object&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Are you farmiliar with &lt;code&gt;Debounce&lt;/code&gt;? Here is an official demo of &lt;code&gt;customRef&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useDebouncedRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;timeout&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;customRef&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;track&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;track&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt;
          &lt;span class="nx"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;setup&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;useDebouncedRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;some text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. v-enter-from / v-leave-from
&lt;/h2&gt;

&lt;p&gt;In Vue 2, the &lt;code&gt;&amp;lt;Transition&amp;gt;&lt;/code&gt; component helps handle the component &lt;code&gt;animation&lt;/code&gt; / &lt;code&gt;transition&lt;/code&gt;. But the component property &lt;code&gt;v-enter-active&lt;/code&gt; &lt;code&gt;v-enter&lt;/code&gt; &lt;code&gt;v-enter-to&lt;/code&gt; were quite ambiguous to me. Sometimes I'm confused which happens first.&lt;/p&gt;

&lt;p&gt;Now in Vue 3, those transition property names became more unified and intuitive.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;v-enter&lt;/code&gt; =&amp;gt; &lt;code&gt;v-enter-from&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;v-leave&lt;/code&gt; =&amp;gt; &lt;code&gt;v-leave-from&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;transition&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"fade"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;v-show=&lt;/span&gt;&lt;span class="s"&gt;"show"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;fade transition&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/transition&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;reactive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;toRefs&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;setup&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;reactive&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;show&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;show&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;show&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;toRefs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
&lt;span class="nc"&gt;.fade-enter-from&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nc"&gt;.fade-leave-to&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.fade-enter-to&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nc"&gt;.fade-leave-from&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.fade-enter-active&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nc"&gt;.fade-leave-active&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;opacity&lt;/span&gt; &lt;span class="m"&gt;2000ms&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The transition order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;v-enter-from&lt;/code&gt; (v-enter)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;v-enter-active&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;v-enter-to&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;v-leave-from&lt;/code&gt; (v-leave)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;v-leave-active&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;v-leave-to&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I believe this is much easier to understand, isn't it?&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Allow Multiple Root Element
&lt;/h2&gt;

&lt;p&gt;Vue 2 throws errors on multiple root element. All elements must be nested within one root element in the template.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Error --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;pitayan&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;blog&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- One Root Element only --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;pitayan&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;blog&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Vue 3 removed this annoying usage. I think this is extremely helpful when you really don't want to nest your elements within a "container" parent. Sometimes all you need is maybe just to insert those bare elements into the right place.&lt;/p&gt;

&lt;p&gt;This works similarly to the &lt;a href="https://reactjs.org/docs/fragments.html"&gt;React Fragments&lt;/a&gt; which helps mitigate the nesting issues.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Vue 3 Multiple Root Element --&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- Okay --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;pitayan&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;blog&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. "Filters" is Deprecated(Removed)
&lt;/h2&gt;

&lt;p&gt;I think a lot of people think that &lt;code&gt;filters&lt;/code&gt; is maybe an awesome feature of Vue.js. It indeed works well in Vue's template engine. (For example, data formatting / calculation etc).&lt;/p&gt;

&lt;p&gt;Let's see how Vue 3 doc explains why &lt;code&gt;filters&lt;/code&gt; is removed:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;While this seems like a convenience, it requires a custom syntax that breaks the assumption of expressions inside of curly braces being "just JavaScript," which has both learning and implementation costs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I believe it's nothing bad for development without the &lt;code&gt;filters&lt;/code&gt;, even though it may cost you extra time on migrating to Vue 3. In my projects, the appearance of &lt;code&gt;filters&lt;/code&gt; is pretty a rare case since I could replace such functionality with a &lt;code&gt;method&lt;/code&gt; or &lt;code&gt;computed&lt;/code&gt; easily. Because in my opinion, &lt;code&gt;method&lt;/code&gt; / &lt;code&gt;computed&lt;/code&gt; has higher readability than the &lt;code&gt;filters&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- Deprecated (removed) &amp;amp; Error --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;{{ count | double }}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;

  &lt;span class="c"&gt;&amp;lt;!-- If you have to use fiter, make it a function --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;{{ double(count) }}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Not working&lt;/span&gt;
  &lt;span class="na"&gt;filters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;double&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;setup&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;double&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. New Async Component: Suspense
&lt;/h2&gt;

&lt;p&gt;This is perhaps the only new feature of Vue 3 that may be changed even after official release. The inspiration is also from &lt;a href="https://reactjs.org/docs/concurrent-mode-suspense.html"&gt;React Suspense&lt;/a&gt;. So the usage scenario would be the same in my opinion.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LGk6fAe2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/94e2ivgvg1znf6k2v7f3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LGk6fAe2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/94e2ivgvg1znf6k2v7f3.png" alt="suspense experimental feature" width="880" height="62"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Do you remember how you render the asynchronous data previously in Vue 2? I think &lt;code&gt;v-if&lt;/code&gt; / &lt;code&gt;v-else&lt;/code&gt; should be the answer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;v-for=&lt;/span&gt;&lt;span class="s"&gt;"i in items"&lt;/span&gt; &lt;span class="na"&gt;:key=&lt;/span&gt;&lt;span class="s"&gt;"i"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ i }}&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;v-else&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;loading...&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;mounted&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;one&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;two&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;Suspense&lt;/code&gt; component, you can do it without handling conditions yourself. By setting up the &lt;code&gt;default&lt;/code&gt; and &lt;code&gt;fallback&lt;/code&gt; slot, the &lt;code&gt;Suspense&lt;/code&gt; component will handle the async event automatically.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;suspense&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;#default&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;v-for=&lt;/span&gt;&lt;span class="s"&gt;"i in items"&lt;/span&gt; &lt;span class="na"&gt;:key=&lt;/span&gt;&lt;span class="s"&gt;"i"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ i }}&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;#fallback&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      Loading...
    &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/suspense&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;setup&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;one&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;two&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;items&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. Display it elsewhere: Teleport
&lt;/h2&gt;

&lt;p&gt;It is another cool stuff based on &lt;a href="https://reactjs.org/docs/portals.html"&gt;React Portals&lt;/a&gt;. It provides the ability to insert the component to a target DOM Node.&lt;/p&gt;

&lt;p&gt;What we do in Vue 2 to insert a custom component in &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; (Of course there is a Vue 3rd party plugin &lt;a href="https://portal-vue.linusb.org"&gt;PortalVue&lt;/a&gt; providing such functionality):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Vue&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Ctor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;div&amp;gt;hello world&amp;lt;/div&amp;gt;`&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Ctor&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;$mount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;To use such feature in Vue 3, wrap your target component within &lt;code&gt;&amp;lt;Teleport&amp;gt;&lt;/code&gt; and define the destination Node (querySelector) in &lt;code&gt;to&lt;/code&gt; property.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Teleport&lt;/span&gt; &lt;span class="na"&gt;to=&lt;/span&gt;&lt;span class="s"&gt;"body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;Pitayan&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/Teleport&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  8. Allow Multiple v-model
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;v-model&lt;/code&gt; is used for data two-way bindings in form elements or even custom components. In Vue 2, a custom component can only have one &lt;code&gt;v-model&lt;/code&gt; in the tag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;my-input-form&lt;/span&gt; &lt;span class="na"&gt;v-model=&lt;/span&gt;&lt;span class="s"&gt;"input"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vue 3 removed the limitation and allows you to have multiple &lt;code&gt;v-model&lt;/code&gt; so that you could specify the bindings separately for more input elements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;my-input-form&lt;/span&gt;
    &lt;span class="na"&gt;v-model:first=&lt;/span&gt;&lt;span class="s"&gt;"inputFirst"&lt;/span&gt;
    &lt;span class="na"&gt;v-model:second=&lt;/span&gt;&lt;span class="s"&gt;"inputSecond"&lt;/span&gt;
    &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  9. Global APIs
&lt;/h2&gt;

&lt;p&gt;Vue 3 offers some new APIs to help us control the components and instances better.&lt;/p&gt;

&lt;h3&gt;
  
  
  createApp
&lt;/h3&gt;

&lt;p&gt;In Vue 2, &lt;code&gt;Vue&lt;/code&gt; can be used as constructor to return an instance Object. In Vue 3, you could use &lt;code&gt;createApp&lt;/code&gt; function instead. The behavior is actually the same.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Vue 2&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Vue&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/src/App&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;el&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;App&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Vue 3&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createApp&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/src/App&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What about those global methods like &lt;code&gt;extend&lt;/code&gt; &lt;code&gt;component&lt;/code&gt;&amp;amp;nbsp&lt;code&gt;mixin&lt;/code&gt; and &lt;code&gt;directive&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;Same, but you need to use the instance method instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Global methods&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mixin&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;directive&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  nextTick
&lt;/h3&gt;

&lt;p&gt;I think &lt;code&gt;nextTick&lt;/code&gt; is a frequently used API since a lot of the logics are actually asynchronous and they need to be arraged to the next DOM update cycle.&lt;/p&gt;

&lt;p&gt;In Vue 2, &lt;code&gt;nextTick&lt;/code&gt; is an instance method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...,&lt;/span&gt;
  &lt;span class="nx"&gt;mounted&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$nextTick&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pitayan&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vue 3 allows to you use &lt;code&gt;nextTick&lt;/code&gt; as an independent function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// nextTick function type&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;declare&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;nextTick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// An official doc Example&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;nextTick&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;setup&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello, Pitayan!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;changeMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;newMessage&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newMessage&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;nextTick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Now DOM is updated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Other Helper Functions
&lt;/h3&gt;

&lt;p&gt;These new APIs will be extremely helpful when you need extra controls for much more abstracted scenarios. I personally think that they can be frequently used in the 3rd party libraries.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;h:&lt;/strong&gt; return virtual node&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;createRenderer:&lt;/strong&gt; custom renderer that can be used for cross-environment purposes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;defineComponent:&lt;/strong&gt; type the Object passed in&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;defineAsyncComponent:&lt;/strong&gt; load async component when necessary&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;resolveComponent:&lt;/strong&gt; resolve a component within the current instance scope&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;resolveDynamicComponent:&lt;/strong&gt; resolve a dynamic component within the current instance scope&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;resolveDirective:&lt;/strong&gt; get a &lt;code&gt;directive&lt;/code&gt; from the current instance scope&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;withDirectives:&lt;/strong&gt; applies &lt;code&gt;directive&lt;/code&gt; to a &lt;code&gt;VNode&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;I'm very happy and honored to vitness the growth of Vue.js 2.x =&amp;gt; 3.x. Vue team concludes what was not possible natively in Vue 2 and made them possible in Vue 3. As I could see that there are many familar stuffs from Vue 3's code base.&lt;/p&gt;

&lt;p&gt;It's not hard to tell that Vue 3 is a much more solid framework. It provides a new and simpler way to organize your source code,  meanwhile smaller and faster. And under the help of &lt;code&gt;Typescript&lt;/code&gt; and their new features for instance composition API, projects' structure can become very much different than before. Which I believe is a positive impact to the front end community.&lt;/p&gt;

&lt;p&gt;That's all for the Vue 3's new feature.&lt;/p&gt;

&lt;p&gt;If you think this article is great. Please share it to the social networks. Thanks for reading.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://v3.vuejs.org/"&gt;https://v3.vuejs.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vuejs.org/v2/"&gt;https://vuejs.org/v2/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://composition-api.vuejs.org/"&gt;https://composition-api.vuejs.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://reactjs.org/docs/"&gt;https://reactjs.org/docs/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Originally on &lt;a href="https://pitayan.com/posts/vue-next-features/?ref=dev.to"&gt;Pitayan.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pitayan.com/posts/vue-next-features/?ref=dev.to"&gt;https://pitayan.com/posts/vue-next-features/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vue</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
