<?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: Michał Kuncio</title>
    <description>The latest articles on DEV Community by Michał Kuncio (@michalkuncio).</description>
    <link>https://dev.to/michalkuncio</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%2F516704%2F5b988a7a-841b-4e06-8155-68295ab8f2da.png</url>
      <title>DEV Community: Michał Kuncio</title>
      <link>https://dev.to/michalkuncio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/michalkuncio"/>
    <language>en</language>
    <item>
      <title>A collection of FREE Vue.js, Nuxt and Vite tips is OUT!</title>
      <dc:creator>Michał Kuncio</dc:creator>
      <pubDate>Thu, 07 Mar 2024 18:07:47 +0000</pubDate>
      <link>https://dev.to/michalkuncio/a-collection-of-free-vuejs-nuxt-and-vite-tips-is-out-c70</link>
      <guid>https://dev.to/michalkuncio/a-collection-of-free-vuejs-nuxt-and-vite-tips-is-out-c70</guid>
      <description>&lt;p&gt;Hello everyone,&lt;br&gt;
For some time, I have been sharing Vue and Nuxt-related tips on my &lt;a href="https://twitter.com/michalkuncio"&gt;Twitter profile&lt;/a&gt;. I have received great feedback and thought I should organize all the tips, making them searchable and discoverable for people without an Twitter account. I wanted to give something back to this awesome community I'm a part of by sharing some tips I've learned over the years.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check out the website here:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://vuejstips.com"&gt;https://vuejstips.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you! 💚&lt;/p&gt;

</description>
      <category>vue</category>
      <category>nuxt</category>
      <category>vite</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Looking for your first easy open-source contribution? 🤔 Contribute to Frontend History! 📕</title>
      <dc:creator>Michał Kuncio</dc:creator>
      <pubDate>Wed, 24 Jan 2024 18:47:19 +0000</pubDate>
      <link>https://dev.to/michalkuncio/looking-for-your-first-easy-open-source-contribution-contribute-to-frontend-history-44me</link>
      <guid>https://dev.to/michalkuncio/looking-for-your-first-easy-open-source-contribution-contribute-to-frontend-history-44me</guid>
      <description>&lt;p&gt;Many people would like to make their first contributions to open source, but sometimes it's not easy to find a repository that matches their skill level with current issues 🤔.&lt;/p&gt;

&lt;p&gt;If you would like to help open source and make your first ever contributions, I would love to see your pull requests on my new project &lt;a href="https://frontendhistory.com/"&gt;Frontend History&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;How can you help?&lt;/strong&gt; Frontend History is a calendar showcasing the most important events in the history of frontend development. It's not that easy to keep track of everything happening now and document everything from the past. I would really appreciate it if you could add some new events! 🙏🏻&lt;/p&gt;

&lt;p&gt;Please visit the &lt;a href="https://github.com/michalkuncio/frontendhistory"&gt;GitHub repository page&lt;/a&gt; and see how you can contribute! 🎉&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>vue</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Please stop using reactive() in Vue 3 Composition API 🙏🏻</title>
      <dc:creator>Michał Kuncio</dc:creator>
      <pubDate>Thu, 28 Dec 2023 19:38:47 +0000</pubDate>
      <link>https://dev.to/michalkuncio/please-stop-using-reactive-in-vue-3-composition-api-4hg7</link>
      <guid>https://dev.to/michalkuncio/please-stop-using-reactive-in-vue-3-composition-api-4hg7</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;When Vue 3 introduced the Composition API, I was really excited about this new way of building components in my favorite framework. And then I was even more excited when &lt;strong&gt;script setup&lt;/strong&gt; came out. I love how reactivity works in Vue 3, and in my opinion, it's the simplest and most elegant approach out of all major frameworks. But there is this one thing that we see very often: "Should I use ref or reactive?", "When should I use ref or reactive?", etc. These questions come from people with varying levels of experience, and there are some battles over the internet where people are trying to create "rules of thumb" for which scenario you should use &lt;strong&gt;ref()&lt;/strong&gt; or &lt;strong&gt;reactive()&lt;/strong&gt;. I've seen some statements like "ref for primitives, reactive for objects and arrays," and let's put it mildly, I don't agree 😀. Why overcomplicate something that should be so damn easy? It's easy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Just always use ref()
&lt;/h2&gt;

&lt;p&gt;Why? Because &lt;strong&gt;ref()&lt;/strong&gt; can do everything that &lt;strong&gt;reactive()&lt;/strong&gt; can, but &lt;strong&gt;reactive()&lt;/strong&gt; can't do anything that &lt;strong&gt;ref()&lt;/strong&gt; can. So the first question is, why would you mix these different reactivity functions?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"ts"&lt;/span&gt;&lt;span class="nt"&gt;&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="nx"&gt;reactive&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="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchPhrase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;matchCaseSensivity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;includeIgnoredItems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;showAdvancedSearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"ts"&lt;/span&gt;&lt;span class="nt"&gt;&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="nx"&gt;reactive&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="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchPhrase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;reactive&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;matchCaseSensivity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;includeIgnoredItems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;showAdvancedSearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;If you create artificial rules like "ref for primitives, reactive for objects and arrays," you introduce unnecessary mental overhead by having to make that decision every time. However, you might ask, "If I can use ref for everything, why does reactive exist?" That's a good question. When using &lt;strong&gt;ref()&lt;/strong&gt;, you have to access the value through the &lt;strong&gt;.value&lt;/strong&gt; property.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"ts"&lt;/span&gt;&lt;span class="nt"&gt;&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="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchPhrase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;clearSearchPhrase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;searchPhrase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;same with objects and arrays:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"ts"&lt;/span&gt;&lt;span class="nt"&gt;&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="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newItemName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;()&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="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newItemName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if you would like to use &lt;strong&gt;reactive()&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"ts"&lt;/span&gt;&lt;span class="nt"&gt;&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="nx"&gt;reactive&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="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newItemName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;reactive&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;()&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="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newItemName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;strong&gt;Reactive&lt;/strong&gt;, you don't have to use &lt;strong&gt;'.value'&lt;/strong&gt; to access the value of a reactive variable. Someone might say, "Oh, so it's better than ref! I don't want to add .value every time." I can sort of understand that, but take a look at the example above one more time. Can you see the problem? Sometimes it's &lt;strong&gt;ref()&lt;/strong&gt;, sometimes it's &lt;strong&gt;reactive()&lt;/strong&gt;. Sometimes it's &lt;strong&gt;'.value'&lt;/strong&gt;, sometimes not. In large codebases, it can be confusing.&lt;/p&gt;

&lt;p&gt;I think the necessity of using &lt;strong&gt;.value&lt;/strong&gt; makes you more aware of when you are using reactive variables or not. It's easy to search the codebase. Trust me, I saw a lot of bugs produced by forgotten '.value' or '.value' being present where it should be because someone used &lt;strong&gt;reactive()&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keeping it short: &lt;code&gt;ref&lt;/code&gt; is more universal, and you can create the whole project with &lt;code&gt;ref()&lt;/code&gt; only to make your code consistent. When you decide to use &lt;code&gt;reactive()&lt;/code&gt;, you will also have to use &lt;code&gt;ref()&lt;/code&gt;, and your codebase will be mixed with different approaches, which can cause a lot of bugs.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Another limitation of &lt;strong&gt;Reactive&lt;/strong&gt; is the fact that it can't replace the entire object, while &lt;strong&gt;Ref&lt;/strong&gt; can.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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="c1"&gt;// the above reference ({ count: 0 }) is no longer being tracked&lt;/span&gt;
&lt;span class="c1"&gt;// (reactivity connection is lost!)&lt;/span&gt;
&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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;1&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are still not convinced, let's check if maybe the Vue docs are saying something about the preferred way.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://vuejs.org/guide/essentials/reactivity-fundamentals#ref"&gt;Oh yes!&lt;/a&gt;, the official docs statement is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;"In Composition API, the recommended way to declare reactive state is using the ref() function"&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And one last thing: I understand that there might be super rare edge cases, especially for library authors, where &lt;strong&gt;reactive&lt;/strong&gt; might be a better choice. If you think that, in a particular scenario, &lt;strong&gt;reactive&lt;/strong&gt; is the better option and you are really confident about it, then go for it! My point is that &lt;strong&gt;ref&lt;/strong&gt; should be your default choice, and if somehow you end up with this super rare edge case, you can go with &lt;strong&gt;reactive&lt;/strong&gt;`. Let's make it easy and not overthink this, making it easier for other people working on the same project. 🙏🏻&lt;/p&gt;




&lt;p&gt;⭐ &lt;strong&gt;&lt;em&gt;If you like my posts, please follow me on Twitter:&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://twitter.com/michalkuncio"&gt;https://twitter.com/michalkuncio&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vue</category>
      <category>webdev</category>
    </item>
    <item>
      <title>You can help write down the history of frontend! Contributions are welcomed 🎉</title>
      <dc:creator>Michał Kuncio</dc:creator>
      <pubDate>Sat, 16 Dec 2023 12:48:09 +0000</pubDate>
      <link>https://dev.to/michalkuncio/you-can-help-write-down-the-history-of-frontend-contributions-are-welcomed-2fp4</link>
      <guid>https://dev.to/michalkuncio/you-can-help-write-down-the-history-of-frontend-contributions-are-welcomed-2fp4</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;I just released my new side project called &lt;a href="https://frontendhistory.com/"&gt;Frontend History&lt;/a&gt;. It's open source and contributions are warmly welcomed! 🎉 Here is the link to the &lt;a href="https://github.com/michalkuncio/frontendhistory"&gt;repository&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;The frontend changes rapidly, with new libraries being released daily, and some features achieving full browser support. Likewise, some libraries and browsers become deprecated. What if we had something like a calendar that cataloged all significant events in the frontend world? This would allow us to stay informed about recent news and explore the distant history of frontend. It would be great to have a single comprehensive repository detailing the entire history of frontend development.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;I want to contribute and add some new items. Which items will be accepted?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you think it's important to the frontend community, go ahead and add it. Adding JS libraries can be a tad trickier because if we were to include every single JS package in this calendar, it'd be way too big. I think we should only list the relevant packages here, so you got to decide for yourself if a library is worth adding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What stack is used here?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nuxt&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why not Astro, Tailwind, HTMX, HTML, XYZ?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I love those tools but I feel the most comfortable with Vue and Nuxt&lt;/p&gt;

&lt;h2&gt;
  
  
  Contributions
&lt;/h2&gt;

&lt;p&gt;This is a long-term community project that will be as valuable as its contributions. Anyone can contribute and help write down the history of Frontend.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to contribute?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Create a separate branch originating from &lt;strong&gt;main&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Create a pull request from your branch to &lt;strong&gt;main&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;For new history entries, please add &lt;strong&gt;[History items]&lt;/strong&gt; at the end of the PR title&lt;/li&gt;
&lt;li&gt;For other issues or improvements, don't you don't have to add any label in the PR title&lt;/li&gt;
&lt;li&gt;For new history entries, navigate to the appropriate year inside &lt;code&gt;/data&lt;/code&gt; directory&lt;/li&gt;
&lt;li&gt;data should follow chronological order, there is no additional sorting&lt;/li&gt;
&lt;li&gt;It should follow the the following structure:
&lt;/li&gt;
&lt;/ul&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="na"&gt;year&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2004&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="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2004-11-09&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;First version of Firefox released&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;link&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://en.wikipedia.org/wiki/Firefox&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firefox&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;ul&gt;
&lt;li&gt;If you are adding a new type of history item, you can also add the SVG icon to &lt;code&gt;components/icons&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Please note that new history items without the link with date confirmation won't be accepted&lt;/li&gt;
&lt;li&gt;Add the repository owner as a reviewer.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>frontend</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>The Ultimate Guide to Raycast Productivity for Developers</title>
      <dc:creator>Michał Kuncio</dc:creator>
      <pubDate>Wed, 13 Dec 2023 18:58:06 +0000</pubDate>
      <link>https://dev.to/michalkuncio/the-ultimate-guide-to-raycast-productivity-for-developers-o4a</link>
      <guid>https://dev.to/michalkuncio/the-ultimate-guide-to-raycast-productivity-for-developers-o4a</guid>
      <description>&lt;h2&gt;
  
  
  What is Raycast?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.raycast.com/" rel="noopener noreferrer"&gt;Raycast&lt;/a&gt; is an awesome productivity launcher for macOS, and I have to say, it has completely transformed my daily workflow. I won't copy and paste any fancy marketing stuff here because Raycast's landing page already does a fantastic job of explaining it. But let me tell you, there are tons of cool articles about Raycast out there. Personally, I've noticed that I use some of its features in "chains" and I've developed a strong muscle memory for them. So, I wanted to share a few of my favorite workflows for development and content creation. To me, a workflow is a set of Raycast commands that I use every single day, from the moment I start my computer to the very end of the process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's start!&lt;/strong&gt; 💪🏻&lt;/p&gt;

&lt;h2&gt;
  
  
  Development workflow
&lt;/h2&gt;

&lt;p&gt;Lately, I've been working on my personal project &lt;a href="https://frontendhistory.com/" rel="noopener noreferrer"&gt;frontendhistory.com&lt;/a&gt; and I will explain most of my development workflow based on this project. &lt;/p&gt;

&lt;h3&gt;
  
  
  Open / switch projects in Visual Studio Code 🧑🏻‍💻
&lt;/h3&gt;

&lt;p&gt;I enjoy having multiple projects open in the same VS Code window and using project tabs. Whether I'm outside of VS Code or already have it open, it's easier to switch or open projects using the &lt;strong&gt;Visual Studio Code&lt;/strong&gt; extension for Raycast. Simply use the "Search Recent Projects" command to search and navigate directly to the desired project from Raycast!&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Window management 🪟
&lt;/h3&gt;

&lt;p&gt;Because I prefer to use a single display for development, I like to split the screen between the browser and code editor. Raycast has built-in window management commands, and you can easily position your windows. I'm simply focusing on my browser and using the &lt;strong&gt;"Left half"&lt;/strong&gt; command.&lt;/p&gt;

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

&lt;p&gt;You can notice that I'm using the "lh" shortcut.&lt;/p&gt;

&lt;p&gt;The same applies if you want to position the window to the right half of the screen.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Linear tasks management ✅
&lt;/h3&gt;

&lt;p&gt;Even for small personal projects, I like to use project management software to keep things organized. I'm using Linear, and luckily for me, there is an extension for that! Let's type &lt;strong&gt;"Linear"&lt;/strong&gt; and see some commands.&lt;/p&gt;

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

&lt;p&gt;Let's check assigned issues:&lt;/p&gt;

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

&lt;p&gt;You can see that I have one task assigned, and I can basically do everything without using Raycast. This includes editing tasks, changing status, or reassigning them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set pomodoro focus time 🍅
&lt;/h3&gt;

&lt;p&gt;Okay, it's time to start working! I like to work in 25-minute focus blocks using the &lt;strong&gt;Pomodoro technique&lt;/strong&gt;. You can control the timers thanks to the &lt;strong&gt;Pomodoro&lt;/strong&gt; extension.&lt;/p&gt;

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

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

&lt;h3&gt;
  
  
  Tailwind docs 💨
&lt;/h3&gt;

&lt;p&gt;There are some &lt;strong&gt;Tailwind&lt;/strong&gt; classes that I just can't remember no matter how hard I will try. That's why the &lt;strong&gt;Tailwind&lt;/strong&gt; extension is so handy. You can search through classes, colors and components.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Can I use ✅❌
&lt;/h3&gt;

&lt;p&gt;Checking browser compatibility is an indispensable part of a frontend developer's life. I love how easy it is to verify if a feature you want to use is supported across all major browsers.&lt;/p&gt;

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

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

&lt;h3&gt;
  
  
  Search SVG icons 🔍
&lt;/h3&gt;

&lt;p&gt;In my side project &lt;a href="https://frontendhistory.com/" rel="noopener noreferrer"&gt;frontendhistory.com&lt;/a&gt;, I am using a lot of open-source icons. The &lt;strong&gt;Iconify&lt;/strong&gt; extension has dramatically improved my workflow and made searching for specific icons really easy!&lt;/p&gt;

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

&lt;h3&gt;
  
  
  PX to REM conversion ↔️
&lt;/h3&gt;

&lt;p&gt;Want to convert pixels (PX) to rems (REM) or vice versa? You don't even need an extension for that. Just type "20px to rem" into the Raycast field, and it's working out of the box. Feels like magic!&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Vue JS docs 💚
&lt;/h3&gt;

&lt;p&gt;There is no secret that I love Vue. That's why I appreciate the &lt;strong&gt;Vue.js&lt;/strong&gt; extension, from which I can search the official docs.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Clipboard history 📜
&lt;/h3&gt;

&lt;p&gt;This one is pretty self-explanatory. Please forgive me for not showing you my clipboard history, but trust me, you need it because it works great!&lt;/p&gt;

&lt;h3&gt;
  
  
  Quick AI (Pro) ✨
&lt;/h3&gt;

&lt;p&gt;Quick AI is a part of the Pro plan. It's absolutely worth it, given the fact that you basically have an AI assistant integrated into your OS. Just open Raycast, type your prompt, hit the TAB key, and you will see the results. No need to open any extension; it works straight away! Quick AI is not only limited to 2021, so you will receive almost real-time results.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  AI Chat (Pro) 💬
&lt;/h3&gt;

&lt;p&gt;Same as Quick AI, AI Chat is also a part of the Pro plan. Sometimes it's more convenient to have a ChatGPT-like conversation with more context, and that's why AI Chat is here!&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Content creation workflow
&lt;/h2&gt;

&lt;p&gt;To say that I am a professional content creator is a bit of an exaggeration, but I try to regularly publish content on my &lt;a href="https://michalkuncio.com/" rel="noopener noreferrer"&gt;blog&lt;/a&gt; and &lt;a href="https://twitter.com/michalkuncio" rel="noopener noreferrer"&gt;X&lt;/a&gt;. Because of that, my content creation workflow is pretty simple, but thanks to Raycast, it's so much easier.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create beautiful code snippets 🤩
&lt;/h3&gt;

&lt;p&gt;I really like to share code snippets on Twitter. Thanks to the &lt;strong&gt;ray.so&lt;/strong&gt; extension, I can do it simply by copying some code to the clipboard and using the "Generate image" command.&lt;/p&gt;

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

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

&lt;h3&gt;
  
  
  Emoji picker 💪🏻
&lt;/h3&gt;

&lt;p&gt;I'm not a big fan of the native macOS emoji picker, and that's why I'm using the emoji picker from Raycast. It's faster, can recommend the most frequently used emojis, and the whole UI is much more practical. Just type "Search Emoji and Symbols" – it's built-in!&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Fix spelling and grammmar 🙊
&lt;/h3&gt;

&lt;p&gt;This might be my most used command. I'm not a native English writer, and it's normal to make some grammar or spelling mistakes from time to time. It's incredibly easy to fix those errors in Raycast. Just select the text in any app (could be anything) and use the &lt;strong&gt;Fix spelling and grammar&lt;/strong&gt; command. You will have your text fixed, and what's even more awesome is that you can directly paste and replace your own selection!&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Pro version invitations
&lt;/h2&gt;

&lt;p&gt;Some features described in this article are available in the Pro version only. If you sign up using one of my links, you will get a free month of Raycast Pro, and so will I!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Register and get one month for free!&lt;/em&gt;&lt;/strong&gt; 🎉&lt;/p&gt;

&lt;p&gt;&lt;a href="https://raycast.com/hey/00215c8f" rel="noopener noreferrer"&gt;https://raycast.com/hey/00215c8f&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://raycast.com/hey/41efb76c" rel="noopener noreferrer"&gt;https://raycast.com/hey/41efb76c&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://raycast.com/hey/4fc18d46" rel="noopener noreferrer"&gt;https://raycast.com/hey/4fc18d46&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://raycast.com/hey/582a7995" rel="noopener noreferrer"&gt;https://raycast.com/hey/582a7995&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://raycast.com/hey/808e78a3" rel="noopener noreferrer"&gt;https://raycast.com/hey/808e78a3&lt;/a&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>raycast</category>
      <category>macos</category>
    </item>
    <item>
      <title>What is the NuxtIsland component? 🏝️</title>
      <dc:creator>Michał Kuncio</dc:creator>
      <pubDate>Sat, 28 Oct 2023 16:37:59 +0000</pubDate>
      <link>https://dev.to/michalkuncio/what-is-the-nuxtisland-component-kca</link>
      <guid>https://dev.to/michalkuncio/what-is-the-nuxtisland-component-kca</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;em&gt;Nuxt Island&lt;/em&gt;&lt;/strong&gt; is a cool yet experimental feature of &lt;strong&gt;&lt;em&gt;Nuxt 3&lt;/em&gt;&lt;/strong&gt;. It's a special built-in component that lets you render the component fully on the server which means zero client-side JavaScript served to the browser. Even if you are using SSR and the HTML content is rendered on the server, client-side JS is still served and used during hydration. With the NuxtIsland component, there is no hydration at all.&lt;/p&gt;

&lt;p&gt;When it will come in handy? For example, when we don't need our component to be interactive but we still need some JavaScript logic to make it work. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Let's take a look at some examples:&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;using syntax highlighting library:&lt;/em&gt;&lt;/strong&gt; most of these libraries are quite heavy and we don't need any client-side interactivity when the component is rendered. We might want to get colored syntax from the server and not need any further action regarding syntax highlighting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;using heavy date utility library:&lt;/em&gt;&lt;/strong&gt; libraries like moment.js (and yes, I know that it's heavy and not maintained anymore) are also quite heavy. When we need to parse some date, calculate differences, or check timezones we usually want to make it once and serve it to the user.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;using utility libraries like lodash&lt;/em&gt;&lt;/strong&gt;: with that kind of libraries, we are usually using some utility function like for example converting from snake_case to camelCase and maybe it's not necessary to ship this function to the production bundle?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are great examples of when it may be a good idea to run some JS code on a server, calculate or render something and return it to the browser without any JS. Of course there are some use cases when you may want these libraries used on the client but we will focus on the case when we don't need any interactivity.&lt;/p&gt;

&lt;p&gt;Let's see how we can make it with &lt;strong&gt;&lt;em&gt;NuxtIsland&lt;/em&gt;&lt;/strong&gt; component!&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use the NuxtIsland component?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;NuxtIsland&lt;/em&gt;&lt;/strong&gt; component is a part of the experimental &lt;strong&gt;&lt;em&gt;server components&lt;/em&gt;&lt;/strong&gt; feature of &lt;strong&gt;&lt;em&gt;Nuxt 3&lt;/em&gt;&lt;/strong&gt;. If you want to use server components, you have to enable it in nuxt.config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// nuxt.config.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineNuxtConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;experimental&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;componentIslands&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's test how it works! To better understand how server components work, we will try to use some heavy library to make the difference more visible. Let's install moment.js which is perfect for that regarding the size of this library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;moment &lt;span class="nt"&gt;--save&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make the test, let's create the component called 'Hello.vue':&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- components/Hello.vue --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&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;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Hello&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"ts"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;moment&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;moment&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;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;moment&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MMMM Do YYYY, h:mm:ss a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we are importing the moment.js library and using it to format the current date. Let's use it as a normal component and show it in the &lt;strong&gt;&lt;em&gt;app.vue&lt;/em&gt;&lt;/strong&gt;. Please note that we don't have to import the &lt;em&gt;**Hello.vue&lt;/em&gt;* component, because of Nuxt auto-imports.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- app.vue --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Hello&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's run the project. The rendered component should look like this:&lt;/p&gt;

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

&lt;p&gt;When we examine our network requests, we can see that the component-related client-side script is downloaded by the browser.&lt;/p&gt;

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

&lt;p&gt;Although 4kb is not something to be afraid of, we might ask the question  "Ok, but this component isn't interactive at all. Why do I even need JS for that?".&lt;/p&gt;

&lt;p&gt;Let's fix it with &lt;strong&gt;&lt;em&gt;NuxtIsland&lt;/em&gt;&lt;/strong&gt;! 🏝️&lt;/p&gt;

&lt;p&gt;Remember our previously created &lt;strong&gt;&lt;em&gt;Hello.vue&lt;/em&gt;&lt;/strong&gt; component? Let's move it from &lt;strong&gt;&lt;em&gt;/components&lt;/em&gt;&lt;/strong&gt; to &lt;strong&gt;&lt;em&gt;/components/islands&lt;/em&gt;&lt;/strong&gt; directory. Now inside the &lt;strong&gt;&lt;em&gt;app.vue&lt;/em&gt;&lt;/strong&gt;, instead of using the &lt;strong&gt;&lt;em&gt;Hello.vue&lt;/em&gt;&lt;/strong&gt; component directly, we will make use of the &lt;strong&gt;&lt;em&gt;NuxtIsland&lt;/em&gt;&lt;/strong&gt; component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- app.vue --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;NuxtIsland&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Hello"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;&lt;em&gt;NuxtIsland&lt;/em&gt;&lt;/strong&gt; component accepts a prop called &lt;strong&gt;&lt;em&gt;"name"&lt;/em&gt;&lt;/strong&gt; which is the name of a component inside &lt;strong&gt;&lt;em&gt;/components/islands&lt;/em&gt;&lt;/strong&gt; directory.&lt;/p&gt;

&lt;p&gt;Now, when we examine network requests again we can see something interesting:&lt;/p&gt;

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

&lt;p&gt;See? No JS at all for this component! 🔥🚀 But all these tests were run on the dev server. What about &lt;strong&gt;&lt;em&gt;production build&lt;/em&gt;&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Production build&lt;/em&gt;&lt;/strong&gt; - classic component:&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Production build&lt;/em&gt;&lt;/strong&gt; - NuxtIsland component:&lt;/p&gt;

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

&lt;p&gt;What?! We saved &lt;strong&gt;&lt;em&gt;45 kB&lt;/em&gt;&lt;/strong&gt; of data thanks to the NuxtIsland component! 🥳&lt;/p&gt;

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

&lt;p&gt;All &lt;strong&gt;&lt;em&gt;Nuxt&lt;/em&gt;&lt;/strong&gt; features around server components are for now experimental but I'm really excited about the Nuxt and server componens future. You can read more about NuxtIsland and Nuxt server components here: &lt;br&gt;
&lt;a href="https://nuxt.com/docs/api/components/nuxt-island" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://nuxt.com/docs/api/components/nuxt-island" rel="noopener noreferrer"&gt;https://nuxt.com/docs/api/components/nuxt-island&lt;/a&gt; &lt;br&gt;
&lt;a href="https://nuxt.com/docs/guide/directory-structure/components" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://nuxt.com/docs/guide/directory-structure/components" rel="noopener noreferrer"&gt;https://nuxt.com/docs/guide/directory-structure/components&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;⭐ &lt;strong&gt;&lt;em&gt;If you like my posts, please follow me on Twitter:&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://twitter.com/michalkuncio" rel="noopener noreferrer"&gt;https://twitter.com/michalkuncio&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nuxt</category>
      <category>vue</category>
      <category>webdev</category>
      <category>frontend</category>
    </item>
    <item>
      <title>How to create a Sitemap in Nuxt Content</title>
      <dc:creator>Michał Kuncio</dc:creator>
      <pubDate>Wed, 11 Oct 2023 17:22:57 +0000</pubDate>
      <link>https://dev.to/michalkuncio/how-to-create-a-sitemap-in-nuxt-content-405d</link>
      <guid>https://dev.to/michalkuncio/how-to-create-a-sitemap-in-nuxt-content-405d</guid>
      <description>&lt;p&gt;&lt;a href="https://content.nuxt.com/"&gt;Nuxt Content&lt;/a&gt; is an amazing tool that makes working with markdown content on Nuxt projects a breeze. Thanks to the power of Nuxt server routes, it's really easy to create a sitemap of our pages.&lt;/p&gt;

&lt;p&gt;Let's take a look at the code.&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;SitemapStream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;streamToPromise&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;sitemap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;serverQueryContent&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;#content/server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;defineEventHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;docs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;serverQueryContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;find&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;staticSites&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="na"&gt;_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&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;_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/about&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;_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/open-source&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;sitemapElements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;staticSites&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;docs&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;sitemap&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;SitemapStream&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VITE_BASE_URL&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;sitemapElements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;sitemap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;write&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;changefreq&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;monthly&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;sitemap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;end&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;streamToPromise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sitemap&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;First of all, let's create a new API route inside &lt;strong&gt;&lt;em&gt;api/routes&lt;/em&gt;&lt;/strong&gt; directory by creating a new file called &lt;strong&gt;&lt;em&gt;'sitemap.ts'&lt;/em&gt;&lt;/strong&gt;. Thanks to that, the RRS feed will be available on &lt;strong&gt;&lt;em&gt;your-domain.com/sitemap.xml&lt;/em&gt;&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Next, inside our &lt;strong&gt;defineEventHandler&lt;/strong&gt;, we have to fetch all articles by using &lt;strong&gt;&lt;em&gt;serverQyeryContent&lt;/em&gt;&lt;/strong&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;docs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;serverQueryContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have any other static pages like for example contact or about, you can create an array with those pages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;staticSites&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="na"&gt;_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&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;_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/about&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;_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/open-source&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;And now, we can combine our articles with static pages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sitemapElements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;staticSites&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next up, let's create a sitemap stream by using the utility function from the &lt;strong&gt;&lt;em&gt;'sitemap'&lt;/em&gt;&lt;/strong&gt; package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sitemap&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;SitemapStream&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VITE_BASE_URL&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when we have a sitemap stream, we can iterate over our sitemap elements and write them to the sitemap stream:&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;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;sitemapElements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;sitemap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;write&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;changefreq&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;monthly&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;Next, we have to fetch all the documents we want to include inside our RRS feed. We can make use of the &lt;strong&gt;serverQueryContent&lt;/strong&gt; function from '#content/server':&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;docs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;serverQueryContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&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;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;where&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;_partial&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next up, we have to iterate over our docs and put every one of them to our previously created feed object:&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;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;BASE_URL&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_path&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we have to end the stream and return our sitemap stream as a Promise by using the &lt;strong&gt;&lt;em&gt;streamToPromise&lt;/em&gt;&lt;/strong&gt; function from the &lt;strong&gt;&lt;em&gt;'sitemap'&lt;/em&gt;&lt;/strong&gt; package.&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;sitemap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;end&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;streamToPromise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sitemap&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, if you would like to prerender the sitemap all you have to do is to specify prerender routes in nuxt config:&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="nx"&gt;defineNuxtConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="na"&gt;nitro&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;prerender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;routes&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;/sitemap.xml&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;And that's all! I love how simple this solution is thanks to Nuxt server routes and nitro prerendering.&lt;/p&gt;

</description>
      <category>nuxt</category>
      <category>vue</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to create an RRS feed in Nuxt Content</title>
      <dc:creator>Michał Kuncio</dc:creator>
      <pubDate>Tue, 03 Oct 2023 19:17:00 +0000</pubDate>
      <link>https://dev.to/michalkuncio/how-to-create-an-rrs-feed-in-nuxt-content-1bg5</link>
      <guid>https://dev.to/michalkuncio/how-to-create-an-rrs-feed-in-nuxt-content-1bg5</guid>
      <description>&lt;p&gt;&lt;a href="https://content.nuxt.com/"&gt;Nuxt Content&lt;/a&gt; is an amazing tool that makes working with markdown content on Nuxt projects a breeze. Thanks to the power of Nuxt server routes, it's really easy to create an RRS feed.&lt;/p&gt;

&lt;p&gt;Let's take a look at the code.&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;RSS&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;rss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;serverQueryContent&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;#content/server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;defineEventHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BASE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://michalkuncio.com&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;feed&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;RSS&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Blog | Michał Kuncio - Modern webdev - the cool parts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;site_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BASE_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;feed_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;BASE_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/rss.xml`&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;docs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;serverQueryContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&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;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;where&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;_partial&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;BASE_URL&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_path&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&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;feedString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;xml&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;indent&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;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content-type&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;text/xml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;feedString&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;First of all, let's create a new API route inside api/routes directory by creating a new file called 'rrs.ts'. Thanks to that, the RRS feed will be available on your-domain.com/rrs.xml. &lt;/p&gt;

&lt;p&gt;Next, inside our &lt;strong&gt;defineEventHandler&lt;/strong&gt;, we will create a new feed by using the &lt;strong&gt;&lt;em&gt;RRS&lt;/em&gt;&lt;/strong&gt; library. Thanks to that library, it will be a little bit easier to parse the RRS feed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;feed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;RSS&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Blog | Michał Kuncio - Modern webdev - the cool parts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;site_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BASE_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;feed_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;BASE_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/rss.xml`&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we have to fetch all the documents we want to include inside our RRS feed. We can make use of &lt;strong&gt;serverQueryContent&lt;/strong&gt; function from '#content/server':&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;docs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;serverQueryContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&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;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;where&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;_partial&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next up, we have to iterate over our docs and put every one of them to our previously created feed object:&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;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;BASE_URL&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_path&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&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;Then, we need an RRS feed string, let's use feed.xml() function for that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;feedString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;xml&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;indent&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, we have to set the correct response headers for browsers to correctly detect xml file and return our feed string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content-type&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;text/xml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;feedString&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it! I love how easy and clean this solution is. Working with Nuxt Content is really an amazing experience. &lt;/p&gt;

</description>
      <category>nuxt</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Create stunning product tours with driver.js 🚖</title>
      <dc:creator>Michał Kuncio</dc:creator>
      <pubDate>Tue, 26 Sep 2023 18:02:17 +0000</pubDate>
      <link>https://dev.to/michalkuncio/create-stunning-product-tours-with-driverjs-42h4</link>
      <guid>https://dev.to/michalkuncio/create-stunning-product-tours-with-driverjs-42h4</guid>
      <description>&lt;h2&gt;
  
  
  Product tours
&lt;/h2&gt;

&lt;p&gt;Sometimes, when you are rolling new features to your customers, it's nice to make a quick showcase of where these new features are located in the UI and how to unlock their full potential. There are many ways of announcing new features like changelogs, dedicated pages or special icons but for me, one of the best solutions is to guide users through these new UI changes so it will be really clear and intuitive. Also by leveraging analytics tools, you can monitor how many users see these features. This technique is called &lt;strong&gt;&lt;em&gt;"product tour"&lt;/em&gt;&lt;/strong&gt; and in basic version it can look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--J4uwSia4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y5duh0lwsush52qil0lt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--J4uwSia4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y5duh0lwsush52qil0lt.png" alt="Product tour example" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Okay, but which library should I use for that?&lt;/p&gt;

&lt;h2&gt;
  
  
  Driver.js
&lt;/h2&gt;

&lt;p&gt;There are many libraries for creating product tours but in my opinion, &lt;a href="https://driverjs.com/"&gt;Driver.js&lt;/a&gt; stands out. Why?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it's the most simple solutions&lt;/li&gt;
&lt;li&gt;it's super intuitive&lt;/li&gt;
&lt;li&gt;it has no external depenencies depencencies&lt;/li&gt;
&lt;li&gt;it has full TS support&lt;/li&gt;
&lt;li&gt;it's 100% customizable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The API is so good, that you can add multi-step product tours in a few lines of code. Let's see how we can make it in &lt;span&gt;Vue.js&lt;/span&gt; (the framework here doesn't matter, the implementations should be identical in other frameworks or pure JS).&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding product tour to our page
&lt;/h2&gt;

&lt;p&gt;First of all, we have to install &lt;strong&gt;&lt;em&gt;driver.js&lt;/em&gt;&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;driver.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's create some product tour steps for my website. On my homepage, I have a theme switcher at the top right corner:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--B2UtQPsP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fmj60qdz1t5uc0dz5lkw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B2UtQPsP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fmj60qdz1t5uc0dz5lkw.png" alt="Theme switcher" width="526" height="158"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This element has a class named &lt;strong&gt;&lt;em&gt;.theme-switcher&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Also, I have a searchbar where you can filter the articles on the homepage:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UN618G2v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/43428y4pznbpfpx6tc64.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UN618G2v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/43428y4pznbpfpx6tc64.png" alt="Search bar" width="800" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This element has a class named &lt;strong&gt;&lt;em&gt;.search-input&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now I want to create a two-step product tour that will highlight those two elements and show some useful descriptions.&lt;/p&gt;

&lt;p&gt;Because all those elements are on a single page (homepage) we can add driver.js-related logic to our homepage component. Let's import the driver js script as well as the &lt;strong&gt;&lt;em&gt;CSS&lt;/em&gt;&lt;/strong&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;// pages/index.vue
&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;ts&lt;/span&gt;&lt;span class="nt"&gt;&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;driver&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;driver.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;driver.js/dist/driver.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have to find a place where we can initialize &lt;strong&gt;&lt;em&gt;driver.js&lt;/em&gt;&lt;/strong&gt;. &lt;strong&gt;&lt;em&gt;OnMounted&lt;/em&gt;&lt;/strong&gt; hook would be perfect for that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;// pages/index.vue
&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;ts&lt;/span&gt;&lt;span class="nt"&gt;&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;driver&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;driver.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;driver.js/dist/driver.css&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;driverJsInit&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;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;driverJsInit&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;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have created a new function &lt;strong&gt;&lt;em&gt;driverJsInit&lt;/em&gt;&lt;/strong&gt; and called it from inside of &lt;strong&gt;&lt;em&gt;onMounted&lt;/em&gt;&lt;/strong&gt; hook. Now let's see how easy it is to add product tours for the 2 elements mentioned above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;// pages/index.vue
&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;ts&lt;/span&gt;&lt;span class="nt"&gt;&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;driver&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;driver.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;driver.js/dist/driver.css&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;driverJsInit&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;driverObj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;showProgress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;steps&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;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.theme-switcher&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;popover&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Theme switcher&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Here you can toggle between dark and light mode&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;side&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;start&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;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.search-input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;popover&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Searchbar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Here you can search for interesting article&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;side&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;start&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;driverObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;drive&lt;/span&gt;&lt;span class="p"&gt;();&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;driverJsInit&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;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even if the API is pretty self-explanatory let's take a look at how it works. First of all, you have to pass a config object to a driver.js function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;// pages/index.vue
&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;ts&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;driverJsInit&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;driverObj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="c1"&gt;// config&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;driverObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;drive&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;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and run the tour by calling &lt;strong&gt;&lt;em&gt;drive()&lt;/em&gt;&lt;/strong&gt; on the driver object. &lt;/p&gt;

&lt;p&gt;You can find more about the configuration &lt;a href="https://driverjs.com/docs/configuration"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Inside the configuration object, we have to set up our steps. The structure looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;steps&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;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.theme-switcher&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;popover&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Theme switcher&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Here you can toggle between dark and light mode&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;side&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;start&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;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.search-input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;popover&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Searchbar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Here you can search for interesting article&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;side&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;start&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;So it's an array of steps where each step has to be connected to a single dom element. We can target this element by using the &lt;strong&gt;&lt;em&gt;element&lt;/em&gt;&lt;/strong&gt; property by assigning a selector in the form of a string. I want to target elements with classes &lt;strong&gt;&lt;em&gt;.theme-switcher&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;.search-input&lt;/em&gt;&lt;/strong&gt;. Next, inside &lt;strong&gt;&lt;em&gt;popover&lt;/em&gt;&lt;/strong&gt; property, you can set everything connected with the popover like title, description, side and align.&lt;/p&gt;

&lt;p&gt;Also, there are more global settings like &lt;strong&gt;&lt;em&gt;showProgress&lt;/em&gt;&lt;/strong&gt; which let you decide if you want to show tour progress inside the popover.&lt;/p&gt;

&lt;p&gt;Let's refresh the page and see what it looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qAdWNPYu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pxxwkrif25gm07qn9qmm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qAdWNPYu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pxxwkrif25gm07qn9qmm.png" alt="Result" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cool! As you can see there is a nice popover with the title and description we previously set and you can navigate to another step by using the next button.&lt;/p&gt;

&lt;h2&gt;
  
  
  Showing product tour only once
&lt;/h2&gt;

&lt;p&gt;Great, we have our product tour up and running. But if you refresh the page you will see it every single time and that's something we don't want. The simplest solution would be setting some localStorage info storing information about the fact that user have seen the full product tour. How do we know about that? There is a special event provided by &lt;strong&gt;&lt;em&gt;driver.js&lt;/em&gt;&lt;/strong&gt; called &lt;strong&gt;&lt;em&gt;onDestroyed&lt;/em&gt;&lt;/strong&gt;. We just have to add it to our configuration object and set a flag in localStorage:&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;onDestroyed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;product_tour_seen&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;true&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;and before initializing our driver js we can check if it's necessary to show the product tour:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;productTourSeen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;product_tour_seen&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;productTourSeen&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Full code:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"ts"&lt;/span&gt;&lt;span class="nt"&gt;&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;driver&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;driver.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;driver.js/dist/driver.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;useHead&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Blog&lt;/span&gt;&lt;span class="dl"&gt;'&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;driverJsInit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;driverJsInit&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;productTourSeen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;product_tour_seen&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;productTourSeen&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;driverObj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;showProgress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;steps&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;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.theme-switcher&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;popover&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Theme switcher&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Here you can toggle between dark and light mode&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;side&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;start&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;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.search-input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;popover&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Searchbar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Here you can search for interesting article&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;side&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;start&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;onDestroyed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;product_tour_seen&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;true&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="nx"&gt;driverObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;drive&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;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Driver.js is a cool library. I love how simple it is. You look at docs, spend a few minutes and know exactly how should you use this library. And it has no dependencies! It will definitely become my go-to solution for product tours.&lt;/p&gt;

&lt;p&gt;⭐ &lt;strong&gt;If you like my posts, please follow me on Twitter:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://twitter.com/michalkuncio"&gt;https://twitter.com/michalkuncio&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>ui</category>
    </item>
    <item>
      <title>Vue is still the only framework capable of this</title>
      <dc:creator>Michał Kuncio</dc:creator>
      <pubDate>Thu, 21 Sep 2023 08:41:07 +0000</pubDate>
      <link>https://dev.to/michalkuncio/vue-is-still-the-only-framework-capable-of-this-16km</link>
      <guid>https://dev.to/michalkuncio/vue-is-still-the-only-framework-capable-of-this-16km</guid>
      <description>&lt;h2&gt;
  
  
  Mutating objects in Javascript
&lt;/h2&gt;

&lt;p&gt;If you want to add a new item in pure Javascript all you have to do is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;items&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;🍕&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;🍟&lt;/span&gt;&lt;span class="dl"&gt;'&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="nx"&gt;push&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;when you inspect the value of the &lt;strong&gt;&lt;em&gt;items&lt;/em&gt;&lt;/strong&gt; array you will see that the original array is mutated and the value is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;🍕&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;🍟&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;🍔&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay, but how does that kind of mutation work in reactive frameworks like &lt;strong&gt;&lt;em&gt;React&lt;/em&gt;&lt;/strong&gt; or &lt;strong&gt;&lt;em&gt;Svelte&lt;/em&gt;&lt;/strong&gt;?&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a new item to an array in React/Svelte
&lt;/h2&gt;

&lt;p&gt;In &lt;strong&gt;&lt;em&gt;React&lt;/em&gt;&lt;/strong&gt; or &lt;strong&gt;&lt;em&gt;Svelte&lt;/em&gt;&lt;/strong&gt; the above solution won't work. That's because of how reactivity works in these frameworks. You can't directly mutate arrays by using native &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push"&gt;Array.prototype.push()&lt;/a&gt;. In both situations, you have to create a new copy of the current array, add the new item to that copy and then reassign the current array to the new copy:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;React:&lt;/em&gt;&lt;/strong&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="nx"&gt;setFood&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;food&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;newFood&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;Svelte:&lt;/em&gt;&lt;/strong&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="nx"&gt;food&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;food&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newFood&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, every time you want to mutate an array, you have to create a new copy and make a reassignment. These are really simple examples but it can quickly become cumbersome if you have nested arrays and objects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a new item to an array in &lt;span&gt;Vue&lt;/span&gt;
&lt;/h2&gt;

&lt;p&gt;In &lt;strong&gt;&lt;em&gt;Vue&lt;/em&gt;&lt;/strong&gt;, the native JS engine behavior just works as expected:&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;food&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;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newFood&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Maybe it doesn't look like a dealbreaker, but for me, this way is way more convenient and natural and the greater difference will be visible in the case of more complicated operations with a lot of updates, especially on nested arrays and objects. I love how clever the reactivity model in Vue is.&lt;/p&gt;

&lt;p&gt;⭐ If you like my posts, please follow me on Twitter:&lt;br&gt;
&lt;a href="https://twitter.com/michalkuncio"&gt;https://twitter.com/michalkuncio&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vue</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>The best feature of Bun is not performance-related</title>
      <dc:creator>Michał Kuncio</dc:creator>
      <pubDate>Tue, 12 Sep 2023 08:30:31 +0000</pubDate>
      <link>https://dev.to/michalkuncio/the-best-feature-of-bun-is-not-performance-related-4f66</link>
      <guid>https://dev.to/michalkuncio/the-best-feature-of-bun-is-not-performance-related-4f66</guid>
      <description>&lt;h2&gt;
  
  
  What is Bun?
&lt;/h2&gt;

&lt;p&gt;Oh, you know what it is 😉 Let's skip this SEO filler and get straight to the point. The best feature of &lt;strong&gt;&lt;em&gt;Bun&lt;/em&gt;&lt;/strong&gt; is how it handles...&lt;/p&gt;

&lt;h2&gt;
  
  
  Module resolution
&lt;/h2&gt;

&lt;p&gt;Anyone who has tried using Node.js with ESM or Typescript surely knows what I'm talking about. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;should I use &lt;strong&gt;&lt;em&gt;JS&lt;/em&gt;&lt;/strong&gt; or &lt;strong&gt;&lt;em&gt;MJS&lt;/em&gt;&lt;/strong&gt; extension?&lt;/li&gt;
&lt;li&gt;if so should I use &lt;code&gt;type: module&lt;/code&gt; inside package.json?&lt;/li&gt;
&lt;li&gt;should I use &lt;code&gt;node --experimental-modules&lt;/code&gt; flag while running the app?&lt;/li&gt;
&lt;li&gt;ok but what about TypeScript? We have &lt;code&gt;compilerOptions.module&lt;/code&gt; there...&lt;/li&gt;
&lt;li&gt;and what If I want to mix ESM and CJS?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The list goes on and on...&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;&lt;em&gt;Bun&lt;/em&gt;&lt;/strong&gt;, you can forget about that madness.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Want to use ESM? &lt;strong&gt;&lt;em&gt;Bun handles it&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Want to use CJS? &lt;strong&gt;&lt;em&gt;Bun handles it&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Want to use JSX/TSX out of the box? &lt;strong&gt;&lt;em&gt;Bun handles it&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⭐️ &lt;strong&gt;&lt;em&gt;And the most important thing:&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;You can mix ESM and CJS imports inside a single file!&lt;/em&gt;&lt;/strong&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="nx"&gt;StuffESM&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./some-esm-module&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;StuffCJS&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="s2"&gt;./some-cjs-module.cjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can be really handy while using some non-ESM node/express packages.&lt;/p&gt;

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

&lt;p&gt;I'm excited about the future of Bun. It has many great features that are widely discussed in the tech space right now. I'm happy that we have 3 serious runtimes (Node, Deno, Bun) because the competition between them should be beneficial to everyone. Don't want to make a switch to Bun/Deno? Thanks to that competition, Node will probably be much better in the next versions and you won't have to switch. Exciting times ahead!&lt;/p&gt;

&lt;p&gt;⭐ If you like my posts, please follow me on Twitter:&lt;br&gt;
&lt;a href="https://twitter.com/michalkuncio"&gt;https://twitter.com/michalkuncio&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>node</category>
      <category>bunjs</category>
    </item>
    <item>
      <title>Nuxt UI is one of the best UI libraries out there</title>
      <dc:creator>Michał Kuncio</dc:creator>
      <pubDate>Thu, 07 Sep 2023 22:45:37 +0000</pubDate>
      <link>https://dev.to/michalkuncio/nuxt-ui-is-one-of-the-best-ui-libraries-out-there-3c4p</link>
      <guid>https://dev.to/michalkuncio/nuxt-ui-is-one-of-the-best-ui-libraries-out-there-3c4p</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;I probably say this too often, but I'm fascinated by how much the Vue ecosystem has been thriving lately. Recent releases of such awesome libraries like &lt;a href="https://formkit.com/"&gt;FormKit&lt;/a&gt; or &lt;a href="https://www.radix-vue.com/"&gt;Radix Vue&lt;/a&gt; are great examples of how well the Vue ecosystem has matured lately.&lt;/p&gt;

&lt;p&gt;If you would like to read more about them, I encourage you to read the articles I have recently published:\&lt;br&gt;
&lt;a href="https://michalkuncio.com/its-insane-how-good-formkit-is"&gt;It's insane how good FormKit is!&lt;/a&gt; \&lt;br&gt;
&lt;a href="https://michalkuncio.com/radix-for-vue-is-finally-available"&gt;Radix for Vue is finally available!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vue ecosystem has many great options to choose from when you are looking for a good UI library. One of the most notable ones are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://primevue.org/"&gt;PrimeVue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vuetifyjs.com/en/"&gt;Vuetify&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://quasar.dev/"&gt;Quasar&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are all great but &lt;strong&gt;&lt;em&gt;Vuetify&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;Quasar&lt;/em&gt;&lt;/strong&gt; have always seemed too opinionated for me. In my opinion, from the list above, &lt;strong&gt;&lt;em&gt;PrimeVue&lt;/em&gt;&lt;/strong&gt; is the most universal and flexible solution. But there's a shiny new library I want to talk about today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nuxt UI
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://ui.nuxt.com/"&gt;Nuxt UI&lt;/a&gt; is a quite new open-source library maintained mostly by &lt;a href="https://nuxtlabs.com/"&gt;Nuxt Labs&lt;/a&gt;. It was recently rebranded from NuxtLabs UI to Nuxt UI and the repo is now under the Nuxt org on GitHub. It's also the first UI library created specifically for Nuxt. From the very beginning, it has become my favorite UI library. Let me tell you why.&lt;/p&gt;

&lt;h3&gt;
  
  
  1) Components are beautiful
&lt;/h3&gt;

&lt;p&gt;The general feeling of default styles is great. The components look fresh, light and elegant at the same time and it's quite hard to do. I'm not a big fan of material UI or bootstrap style and the Nuxt UI feeling hits the perfect spot. Take a look at some &lt;a href="https://ui.nuxt.com/elements/dropdown"&gt;components&lt;/a&gt; in the docs and you will see what I'm talking about.&lt;/p&gt;

&lt;h3&gt;
  
  
  2) Elegant and simple API
&lt;/h3&gt;

&lt;p&gt;Sometimes you take a look at docs, scroll through some components, see at some props and you just know if it fits your style. I love how simple, yet flexible the API for Nuxt UI is. There is no bloat, unnecessary props or tons of ugly wrappers. All you need is there. And the props are so obvious that I can almost guess them without taking a look at the docs.&lt;/p&gt;

&lt;h3&gt;
  
  
  3) Full flexibility in styling
&lt;/h3&gt;

&lt;p&gt;Some libraries are super difficult to customize. You have to overwrite some default styling and sometimes it's a pain in the ass and causing a lot of problems. Nuxt UI is using Tailwind and you have full control over the theming. You can change your theme color in the config file, through CSS variables or directly through component props. Also, there is a special prop "&lt;strong&gt;&lt;em&gt;ui"&lt;/em&gt;&lt;/strong&gt; that lets you customize virtually everything. It's using &lt;strong&gt;&lt;em&gt;tailwind-merge&lt;/em&gt;&lt;/strong&gt; under the hood.&lt;/p&gt;

&lt;h3&gt;
  
  
  4) Fully typed
&lt;/h3&gt;

&lt;p&gt;Nuxt UI is fully typed which means that we have full IDE support with autocomplete and error detection. It's really handy and sometimes you don't have to look at docs because of great intellisense.&lt;/p&gt;

&lt;h3&gt;
  
  
  5) Amazing docs
&lt;/h3&gt;

&lt;p&gt;The docs are well-structured and the components are well-described. Visually it's great but man... Take a look at the &lt;a href="https://ui.nuxt.com/"&gt;homepage&lt;/a&gt;. How beautiful is that!&lt;/p&gt;

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

&lt;p&gt;If you are looking for a component library that feels fresh, modern, elegant and doesn't force you to use an opinionated project structure, &lt;strong&gt;&lt;em&gt;Nuxt UI&lt;/em&gt;&lt;/strong&gt; would be the perfect addition to any &lt;strong&gt;&lt;em&gt;Nuxt&lt;/em&gt;&lt;/strong&gt; project. With tons of useful components and full flexibility over styling, I think it's the best option right now. I'm pretty sure it's just the beginning of this awesome library and we will see many new components and features in the future.&lt;/p&gt;

&lt;p&gt;⭐ &lt;strong&gt;If you like my posts, please follow me on Twitter:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://twitter.com/michalkuncio"&gt;https://twitter.com/michalkuncio&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nuxt</category>
      <category>vue</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
