<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Michael Hoffmann on Medium]]></title>
        <description><![CDATA[Stories by Michael Hoffmann on Medium]]></description>
        <link>https://medium.com/@mokkappsdev?source=rss-b6dc9bc6fff4------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*zewoADFuZnBKolalehVI1Q.jpeg</url>
            <title>Stories by Michael Hoffmann on Medium</title>
            <link>https://medium.com/@mokkappsdev?source=rss-b6dc9bc6fff4------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Thu, 07 May 2026 10:30:09 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@mokkappsdev/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Weekly Vue News #74 — Access DOM in Watcher Callback After Vue Updated It]]></title>
            <link>https://mokkappsdev.medium.com/weekly-vue-news-74-access-dom-in-watcher-callback-after-vue-updated-it-cec0b491058c?source=rss-b6dc9bc6fff4------2</link>
            <guid isPermaLink="false">https://medium.com/p/cec0b491058c</guid>
            <category><![CDATA[nuxt]]></category>
            <category><![CDATA[nuxtjs]]></category>
            <category><![CDATA[vue]]></category>
            <category><![CDATA[vuejs]]></category>
            <dc:creator><![CDATA[Michael Hoffmann]]></dc:creator>
            <pubDate>Thu, 05 Jan 2023 10:56:15 GMT</pubDate>
            <atom:updated>2023-01-05T10:56:15.554Z</atom:updated>
            <content:encoded><![CDATA[<h3>Weekly Vue News #74 — Access DOM in Watcher Callback After Vue Updated It</h3><p>Hi 👋</p><p>Happy New Year 🥳🎉🥂🎊</p><p>📊 Let’s recap my year 2022 📊</p><p>💍 I got married<br> 💸 I had a very successful year as freelancer<br> 📹 I started to create video content<br> 📈 Grew from ~400 to nearly 2000 Twitter followers<br> 📈 Increased LinkedIn follower count to more than 4000 followers</p><p><a href="https://mokkapps.de">mokkapps.de</a></p><p>⭐ Rewrote the whole app using Nuxt 3<br> ⭐ Published 9 blog posts<br> ⭐ Published 45 Vue tips</p><p><a href="https://weekly-vue.news">weekly-vue.news</a></p><p>⭐ Moved my weekly Vue newsletter to a separate domain<br> ⭐ Published 52 newsletter issues</p><p><a href="https://codesnap.dev">codesnap.dev</a></p><p>⭐ Launched my first SaaS<br> ⭐ +200 registered users<br> ⭐ +4000 exported code snippets</p><p>Let’s see what 2023 will bring 🤞🏻</p><p>Of course, you can expect a new Vue tip each week 💪🏻</p><p>Have a nice week ☀️</p><h3>Vue Tip: Access DOM in Watcher Callback After Vue Updated It</h3><p>If you make changes to reactive state in a Vue component, it can trigger both component updates and any watcher callbacks you have created.</p><p>By default, these callbacks are executed before the component updates, so if you try to access the DOM inside a callback, it will be in its pre-update state.</p><p><strong>To access the DOM after Vue has updated it in a watcher callback</strong>, you can use the flush: &#39;post&#39; option:</p><pre>&lt;script setup&gt;<br>watch(source, callback, {<br>  flush: &#39;post&#39;,<br>})<br><br>watchEffect(callback, {<br>  flush: &#39;post&#39;,<br>})<br>&lt;/script&gt;</pre><p>Example for Vue 2 with Options API:</p><pre>&lt;script&gt;<br>export default {<br>  // ...<br>  watch: {<br>    key: {<br>      handler() {},<br>      flush: &#39;post&#39;,<br>    },<br>  },<br>}<br>&lt;/script&gt;</pre><p>Post-flush watchEffect() also has a convenience alias, watchPostEffect():</p><pre>&lt;script setup&gt;<br>import { watchPostEffect } from &#39;vue&#39;<br><br>watchPostEffect(() =&gt; {<br>  /* executed after Vue updates */<br>})<br>&lt;/script&gt;</pre><h3>Curated Vue Content</h3><h3><a href="https://masteringnuxt.com/blog/using-oauth-in-nuxt3">📕 Using OAuth in Nuxt 3</a></h3><p>👉🏻 OAuth is a widely-used industry standard for securely accessing user information without giving access to their passwords.</p><p>👉🏻 Michael gives an overview of how it works, and why he uses it for authentication in Nuxt 3 apps.</p><p><a href="https://medium.com/bauer-kirch/how-to-reuse-one-vue-js-codebase-across-multiple-apps-3d2756a6552">📕 How to reuse one Vue.js codebase across multiple apps</a></p><p>👉🏻 “Reusability is kind of the final boss of software development. (…) everything becomes more complex as soon as something needs to be reused many times.”</p><p><a href="https://www.twilio.com/blog/comparing-nextjs-nestjs-nuxt-gatsby">📕 Next, Nest, Nuxt… Nust?</a></p><p>👉🏻 “This blog post is for everyone looking for their new favorite JavaScript backend framework.”</p><p>👉🏻 Marius explains just what systems like Next and Gatsby do and touches on a few differences.</p><h3>Quote of the week</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/0*31F3KyrGili8sNU9" /></figure><h3>JavaScript Tip: How to Sort an Array of Integers</h3><p>In JavaScript, Array.prototype.sort() sorts the elements of an array in place and returns the reference to the same array, now sorted. The default sort order is ascending, built upon converting the elements into strings and comparing their UTF-16 code unit value sequences.</p><p>sort() mutates the original array. Therefore we use [...numbers] to create a shallow copy of the array in the following example.</p><p>To sort an array of integers, we must provide a compare function that defines the sort order:</p><pre>const numbers = [10, 3, 45, 999, 20]<br><br>const ascendingSortedNumbers = [...numbers].sort((a, b) =&gt; a - b)<br>console.log(ascendingSortedNumbers) // [ 3, 10, 20, 45, 999 ]<br><br>const descendingSortedNumbers = [...numbers].sort((a, b) =&gt; b - a)<br>console.log(descendingSortedNumbers) // [ 999, 45, 20, 10, 3 ]</pre><h3>Curated Web Development Content</h3><h4><a href="https://localghost.dev/blog/building-a-website-like-it-s-1999-in-2022/">📕 Building a website like it’s 1999… in 2022</a></h4><p>👉🏻 Sophie is on a mission this year to bring back the spirit of the old web.</p><p>👉🏻 “(…) and now so many websites look the same. These old personal websites were a reflection of yourself.”</p><p><a href="https://stackoverflow.blog/2022/11/16/biometric-authentication-for-web-devs/">📕 You can add biometric authentication to your webpage. Here’s how.</a></p><p>👉🏻 The easiest way to add biometric authentication to your web application is to use a standard called WebAuthn.</p><p><a href="https://rachelbythebay.com/w/2022/12/02/25k/">📕 Twenty Five Thousand Dollars Of Funny Money</a></p><p>👉🏻 Rachel worked for six weeks at a place that sold ads and fixed a bug that “gave 25 grand worth of funny money to anyone who clicked”.</p><p><a href="https://newrelic.com/blog/how-to-relic/synthetic-user-testing">📕 Build your own synthetic user testing</a></p><p>👉🏻 Syntethic tests simulate the random, unexpected behaviors of your users.</p><p>👉🏻 In this tutorial, Ben shows how to build a synthetic monitoring test for a form on a website.</p><p><a href="https://github.com/chubin/cheat.sh">📕 cheat.sh</a></p><p>👉🏻 Unified access to the best community driven cheat sheets repos of the world.</p><p><a href="https://www.openpdfsign.org/">🛠️ open-pdf-sign</a></p><p>👉🏻 open-pdf-sign allows users to sign PDF files digitally from the command line or webserver.</p><p><a href="https://github.com/Slackadays/clipboard">🛠️ Clipboard</a></p><p>👉🏻 Allows users to cut, copy, and paste anything anywhere from the terminal.</p><p>👉🏻 It works straight out-of-the-box with zero dependencies on Windows, Linux, Android, macOS, and many other operating systems.</p><p><em>Originally published at </em><a href="https://weekly-vue.news/issues/74"><em>https://weekly-vue.news</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cec0b491058c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Weekly Vue News #73 — Pass Custom Arguments to Event Handler Method]]></title>
            <link>https://mokkappsdev.medium.com/weekly-vue-news-73-pass-custom-arguments-to-event-handler-method-aafae0d8c536?source=rss-b6dc9bc6fff4------2</link>
            <guid isPermaLink="false">https://medium.com/p/aafae0d8c536</guid>
            <category><![CDATA[vue]]></category>
            <category><![CDATA[vuejs]]></category>
            <dc:creator><![CDATA[Michael Hoffmann]]></dc:creator>
            <pubDate>Fri, 30 Dec 2022 17:03:15 GMT</pubDate>
            <atom:updated>2022-12-30T17:03:15.056Z</atom:updated>
            <content:encoded><![CDATA[<h3>Weekly Vue News #73 — Pass Custom Arguments to Event Handler Method</h3><p>Published at Dec 26, 2022, 2:00 PM</p><p>Hi 👋</p><p>I deleted my account at <a href="https://www.getrevue.co/">Revue</a> as they will shut down in January 2023.</p><p>This is the first issue that is sent via my custom-built newsletter solution:</p><p>I store the subscriber list on <a href="https://supabase.com">Supabase</a>, manage the content as Markdown files on <a href="https://weekly-vue.news">my Nuxt 3-powered newsletter website</a> and send the emails using <a href="https://aws.amazon.com/ses/">Amazon SES</a>.</p><p>I plan to write a blog post about how I replaced Revue with my custom-built solution.</p><p>Have a nice week ☀️</p><h3>Vue Tip: Pass Custom Arguments to Event Handler Method</h3><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FGx4KaeYlx20%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DGx4KaeYlx20&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FGx4KaeYlx20%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/6426b4904178d28f0b7bceca408fbfa7/href">https://medium.com/media/6426b4904178d28f0b7bceca408fbfa7/href</a></iframe><p>In Vue, we use the v-on (typically shortened with the @ symbol) to listen to DOM events and run some JavaScript code when triggered.</p><p>We can use inline handlers or method handlers if the logic for the event handler is more complex:</p><pre>&lt;script setup&gt;<br>const name = ref(&#39;Vue.js&#39;)<br><br>const greet = (event) =&gt; {<br>  alert(`Hello ${name.value}!`)<br>  if (event) {<br>    alert(event.target.tagName)<br>  }<br>}<br>&lt;/script&gt;<br><br>&lt;template&gt;<br>  &lt;button @click=&quot;greet&quot;&gt;Greet&lt;/button&gt;<br>&lt;/template&gt;</pre><p>Sometimes we need to pass custom arguments to the method and access the original DOM event:</p><pre>&lt;script setup&gt;<br>const name = ref(&#39;Vue.js&#39;)<br><br>const greet = (event, name) =&gt; {<br>  alert(`Hello ${name.value}!`)<br>  if (event) {<br>    alert(event.target.tagName)<br>  }<br>}<br>&lt;/script&gt;<br><br>&lt;template&gt;<br>  &lt;button @click=&quot;greet($event, “Michael”)&quot;&gt;Greet&lt;/button&gt;<br>&lt;/template&gt;</pre><p>The original DOM event is accessible via the unique $event variable. Custom arguments can be added by calling the method in an inline handler instead of directly binding it to a method name.</p><h3>Curated Vue Content</h3><p><a href="https://github.com/LinusBorg/portal-vue">🛠️ PortalVue 3.0</a></p><p>👉🏻 Feature-rich portal plugin for Vue 3.</p><p>👉🏻 “A Portal Component for Vue 3, to render DOM outside of a component, anywhere in the document.”</p><p><a href="https://vuejsnation.com/">📆 Vue.js Nation 2023</a></p><p>👉🏻 It’s all happening 25 &amp; 26 January</p><p>👉🏻 Get to know Quasar, Vuetify 3, Nuxt 3, Pinia, Vite, Vitest, Volar, Vue.js, Typescript, VueUse and more!</p><p>👉🏻 Evan You is hosting the keynote for Vue.js Nation.</p><p>👉🏻 Register free!</p><p><a href="https://github.com/PuruVJ/neodrag">🛠️ neodrag</a></p><p>👉🏻 This drag-and-drop solution includes packages for React, Svelte, Vue, Solid and vanilla JavaScript.</p><h3>Quote of the week</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/0*6T0ssybJdzu1XSto" /></figure><h3>JavaScript Tip: A function that throws an error if a required parameter is missing</h3><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2F4tdRSYnybps%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D4tdRSYnybps&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2F4tdRSYnybps%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/ccd1eb459fea8305a1975dc6785d0b33/href">https://medium.com/media/ccd1eb459fea8305a1975dc6785d0b33/href</a></iframe><p>Default function parameters allow named parameters to be initialized with default values if no value or undefined is passed.</p><p>We can use this approach to write a function that throws an error if a required parameter is missing:</p><pre>const isRequired = () =&gt; {<br>  throw new Error(&#39;Parameter is required!&#39;)<br>}<br><br>const foo = (bar = isRequired()) =&gt; {<br>  console.log(bar)<br>}<br><br>foo() // throws the isRequired error<br>foo(undefined) // throws the isRequired error<br>foo(false) // logs &quot;false&quot;<br>foo(null) // logs &quot;null&quot;<br>foo(&#39;Test&#39;) // logs &quot;true&quot;</pre><h3>Curated Web Development Content</h3><p><a href="https://dev.to/lissy93/super-useful-css-resources-1ba3">📕 Super Useful CSS Resources</a></p><p>👉🏻 A collection of 70 web-based tools that can generate pure CSS without the need for JavaScript or external libraries.</p><p>👉🏻 Categories include property generators, animations, backgrounds, typography, loaders, and layouts.</p><p><a href="https://github.com/nektos/act">🛠️ Act</a></p><p>👉🏻 It allows users to run GitHub Actions locally.</p><p>👉🏻 It allows developers to receive fast feedback and features a local task runner.</p><p>👉🏻 It is available on Windows, macOS, and Linux.</p><p><em>Originally published at </em><a href="https://weekly-vue.news/issues/73/"><em>https://weekly-vue.news</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=aafae0d8c536" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Weekly Vue News — #72 — Avoid Mutating a Prop Directly]]></title>
            <link>https://mokkappsdev.medium.com/weekly-vue-news-72-avoid-mutating-a-prop-directly-ddb8d2216336?source=rss-b6dc9bc6fff4------2</link>
            <guid isPermaLink="false">https://medium.com/p/ddb8d2216336</guid>
            <category><![CDATA[vue]]></category>
            <category><![CDATA[vuejs]]></category>
            <dc:creator><![CDATA[Michael Hoffmann]]></dc:creator>
            <pubDate>Tue, 20 Dec 2022 06:38:17 GMT</pubDate>
            <atom:updated>2022-12-20T06:38:17.606Z</atom:updated>
            <content:encoded><![CDATA[<h3>Weekly Vue News — #72 — Avoid Mutating a Prop Directly</h3><p>Hi 👋</p><p>Unfortunately, my newsletter service (<a href="https://www.getrevue.co">Revue</a> by Twitter) shuts down in January 2023 … in about four weeks….</p><p><strong>Of course, I will continue publishing weekly Vue news!</strong></p><p>I will migrate all existing subscribers to a custom solution: Store the subscriber list on Supabase, manage the content on my <a href="https://weekly-vue.news">Nuxt 3-powered newsletter website</a> and send the emails using Amazon SES.</p><p>Next week’s issue will look quite different but will contain the same high-quality content. If you encounter any problems, <a href="mailto:mail@mokkapps.de">send me a email</a>.</p><p>Have a great week ☀️</p><h3>Vue Tip: Avoid Mutating a Prop Directly</h3><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FZaQZblRUnXs%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DZaQZblRUnXs&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FZaQZblRUnXs%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/0cd99606a6b51c97f81bc6ccc0ebaa3a/href">https://medium.com/media/0cd99606a6b51c97f81bc6ccc0ebaa3a/href</a></iframe><p>If you are using Vue 3 + <a href="https://eslint.vuejs.org/">ESLint</a> and try to mutate a prop in your Vue component, you should see the following error:</p><blockquote>Unexpected mutation of “todo” prop. <em>eslintvue/no-mutating-props</em></blockquote><p>If you are using Vue 2, Vue will throw the following error/warning in your browser’s console:</p><blockquote>[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop’s value.</blockquote><h4>Explanation</h4><p>First, we look at the <a href="https://vuejs.org/guide/components/props.html#one-way-data-flow">official documentation</a> to understand why Vue throws that error.</p><h4>Why do we see the error</h4><blockquote>When objects and arrays are passed as props, while the child component cannot mutate the prop binding, it will be able to mutate the object or array’s nested properties. This is because JavaScript objects and arrays are passed by reference, and it is unreasonably expensive for Vue to prevent such mutations.</blockquote><h4>Why is it a problem</h4><blockquote>The main drawback of such mutations is that it allows the child component to affect the parent state in a way that isn’t obvious to the parent component, potentially making it more difficult to reason about the data flow in the future. <strong>As a best practice, you should avoid such mutations unless the parent and child are tightly coupled by design.</strong></blockquote><h4>Recommended solution</h4><blockquote>In most cases, the child should <a href="https://vuejs.org/guide/components/events.html">emit an event</a> to let the parent perform the mutation.</blockquote><h4><a href="https://mokkapps.de/vue-tips/avoid-mutating-a-prop-directly#demo">Demo</a></h4><p>Let’s look at a code example. I’m using a Todo app to demonstrate the error. The source code is <a href="https://stackblitz.com/edit/vue-tip-avoid-mutating-a-prop-directly-rce9y4">interactively available on StackBlitz</a>.</p><p>Let’s start by taking a look at the TodoList.vue component:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*hqg4K7KmdS9xLwMZ" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><p>TodoList.vue contains a reactive variable todos that includes an array of Todo items. In the template, each item is rendered via TodoItem.vue component:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*Hem2Vq0WVSZffyoX" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><p>Assuming ESLint is <a href="https://eslint.vuejs.org/user-guide/#editor-integrations">correctly configured</a>, you should see the following ESLint error if you open TodoItem.vue in your editor:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*5RYcL5dciIZ17cb1" /></figure><h4>Mutating props is an anti-pattern</h4><p>We want to write components that are easy to maintain.</p><p>In a maintainable component, <strong>only the component itself should be able to change its own state</strong>.</p><p>Additionally, <strong>only the component’s parent should be able to change the props</strong>.</p><p>These two rules are essential to ensure <a href="https://vuejs.org/guide/components/props.html#one-way-data-flow">Vue’s One-Way Data Flow</a> to make our app’s data flow easier to understand.</p><p><strong>⚠️ If we mutate the props, we violate both rules and break Vue’s data flow!</strong></p><p>In addition, every time the parent component is updated, all props in the child component will be refreshed with the latest value.</p><h4>Solution</h4><p><strong>In most cases, the error can be solved using a </strong><a href="https://vuejs.org/guide/essentials/computed.html#computed-properties"><strong>computed property</strong></a><strong>.</strong></p><p>In our example, instead of mutating the prop, we emit an event to the parent. The parent is then responsible for updating the Todo list correctly.</p><p>Let’s use a writeable computed property in TodoItem.vue. Its getter access the prop&#39;s value, and the setter emits an event to the parent:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*84NbD15ZFLRt1ocV" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><p>Finally, we need to react to the emitted event in TodoList.vue and update the todos accordingly:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*oYcVMabAn9te58X5" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><p>The prop is not mutated with this solution, and we correctly use the one-way data flow in our Vue application.</p><p>The amazing <a href="https://twitter.com/MichaelThiessen">Michael Thiessen</a> also wrote <a href="https://michaelnthiessen.com/avoid-mutating-prop-directly/">a detailed article</a> about this topic.</p><h3>Curated Vue Content</h3><h4><a href="https://vitejs.dev/blog/announcing-vite4.html?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Announcing Vite 4</a></h4><p><a href="https://vitejs.dev/blog/announcing-vite4.html">vitejs.dev</a></p><p>👉🏻 Vite is now using Rollup 3, which allowed them to simplify Vite’s internal asset handling and has many improvements</p><h4><a href="https://beholdr.github.io/maska/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter#/">🛠️ Maska 2.1</a></h4><p><a href="https://beholdr.github.io/maska/#/">beholdr.github.io</a></p><p>👉🏻 A zero-dependency input mask</p><p>👉🏻 Happy in vanilla situations, but can also integrate with Vue 2/3.</p><h4><a href="https://harlemjs.com/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">🛠️ Harlem 3.0</a></h4><p><a href="https://harlemjs.com/">harlemjs.com</a></p><p>👉🏻 A simple extensible state management for Vue 3.</p><p>👉🏻 Provides a simple functional API for creating, reading, and mutating state.</p><h3>Quote of the Week</h3><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*ZBYUtTflvzLbBzpM" /></figure><h3>JavaScript Tip: Sum an array with reduce()</h3><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FX6w3voMg-Gg%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DX6w3voMg-Gg&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FX6w3voMg-Gg%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/15aa27eb93b588ea22f9640d463a0a5c/href">https://medium.com/media/15aa27eb93b588ea22f9640d463a0a5c/href</a></iframe><p>The <strong>reduce()</strong> method executes a user-supplied &quot;reducer&quot; callback function on each element of the array, in order, passing in the return value from the calculation on the preceding element. The final result of running the reducer across all elements of the array is a single value.</p><p>The first time that the callback is run there is no “return value of the previous calculation”. If supplied, an initial value may be used in its place. Otherwise the array element at index 0 is used as the initial value and iteration starts from the next element (index 1 instead of index 0).</p><p>Perhaps the easiest-to-understand case for reduce() is to return the sum of all the elements in an array:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*rrMswXM93FpsrG09" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><p>The reducer walks through the array element-by-element, at each step adding the current array value to the result from the previous step (this result is the running sum of all the previous steps) — until there are no more elements to add.</p><h3>Curated Web Development Content</h3><h4><a href="https://jsworldconference.com/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📅 JSWorld Conference 2023</a></h4><p><a href="https://jsworldconference.com/">jsworldconference.com</a></p><p>👉🏻 The largest JS conference in the world, and it’s back in Amsterdam on Feb. 8–10.</p><p>👉🏻 30 talks on Vite, Vue and Svelte by the Creator of Vite and Vue, Evan You and Core Team members.</p><h4><a href="https://antoinemesnil.hashnode.dev/tidy-up-your-es6-imports?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Tidy up your ES6 imports</a></h4><p><a href="https://antoinemesnil.hashnode.dev/tidy-up-your-es6-imports">antoinemesnil.hashnode.dev</a></p><p>Antoinse shows three ways how to tidy up ES6 imports:</p><p>👉🏻 Barrel pattern</p><p>👉🏻 Aliases</p><p>👉🏻 Order imports</p><h4><a href="https://2ality.com/2022/11/testing-static-types-typescript.html?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Testing static types in TypeScript</a></h4><p><a href="https://2ality.com/2022/11/testing-static-types-typescript.html">2ality.com</a></p><p>👉🏻 When it comes to TypeScript code there are far fewer options for testing its compile-type types.</p><h4><a href="https://marvinh.dev/blog/speeding-up-javascript-ecosystem/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Speeding up the JavaScript ecosystem — one library at a time</a></h4><p><a href="https://marvinh.dev/blog/speeding-up-javascript-ecosystem/">marvinh.dev</a></p><p>👉🏻 Most popular libraries can be sped up by avoiding unnecessary type conversions or by avoiding creating functions inside functions.</p><h4><a href="https://github.com/microsoft/TypeScript/issues/51362?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 TypeScript 5.0 Iteration Plan</a></h4><p><a href="https://github.com/microsoft/TypeScript/issues/51362">github.com</a></p><p>👉🏻 Eagerly awaiting TypeScript 5?</p><p>👉🏻 The first beta is due in late January 2023.</p><h4><a href="https://jrsinclair.com/articles/2022/why-would-anyone-need-javascript-generator-functions/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Why would anyone need JavaScript generator functions?</a></h4><p><a href="https://jrsinclair.com/articles/2022/why-would-anyone-need-javascript-generator-functions/">jrsinclair.com</a></p><p>👉🏻 James explains that generator functions in JS may not be essential but they do have utility and can change how you approach certain problems.</p><h4><a href="https://kittygiraudel.com/2022/09/30/templating-in-html/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Templating in HTML</a></h4><p><a href="https://kittygiraudel.com/2022/09/30/templating-in-html/">kittygiraudel.com</a></p><p>👉🏻 Kitty explains why the template element in HTML is pretty handy.</p><h4><a href="https://jvns.ca/blog/2022/12/07/tips-for-analyzing-logs/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Tips for analyzing logs</a></h4><p><a href="https://jvns.ca/blog/2022/12/07/tips-for-analyzing-logs/">jvns.ca</a></p><p>14 useful tips including the following:</p><p>👉🏻 Search for the request’s ID</p><p>👉🏻 Build a timeline</p><h4><a href="https://github.com/ehmicky/modern-errors?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">🛠️ Modern Errors</a></h4><p><a href="https://github.com/ehmicky/modern-errors">github.com</a></p><p>👉🏻 A JS/TS library for handling errors</p><p>👉🏻 It features simple patterns for creating error classes, setting error properties, wrapping or aggregating errors, and separating known and unknown errors.</p><h4><a href="https://embed.im/snow/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">🛠️ Snow.js</a></h4><p><a href="https://embed.im/snow/">embed.im</a></p><p>👉🏻 Add a snow effect to a web page</p><p>👉🏻 It’s that time… (in Germany at least)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ddb8d2216336" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Weekly Vue News — #71 — Dynamically Add & Remove Route While App Is Running]]></title>
            <link>https://mokkappsdev.medium.com/weekly-vue-news-71-dynamically-add-remove-route-while-app-is-running-5509a03ac23d?source=rss-b6dc9bc6fff4------2</link>
            <guid isPermaLink="false">https://medium.com/p/5509a03ac23d</guid>
            <category><![CDATA[vue]]></category>
            <category><![CDATA[newsletter]]></category>
            <category><![CDATA[frontend]]></category>
            <category><![CDATA[vuejs]]></category>
            <dc:creator><![CDATA[Michael Hoffmann]]></dc:creator>
            <pubDate>Tue, 20 Dec 2022 06:37:47 GMT</pubDate>
            <atom:updated>2022-12-20T06:37:47.237Z</atom:updated>
            <content:encoded><![CDATA[<h3>Weekly Vue News — #71 — Dynamically Add &amp; Remove Route While App Is Running</h3><p>Hi 👋</p><p>I’m still busy working on my video content but I found the time to publish a new blog post about a table of contents component for Nuxt 3 and Nuxt Content. You can find the link below.</p><p>I’m also planning to rewrite my <a href="https://github-traffic-viewer.netlify.com/">GitHub Traffic Viewer</a> with Nuxt 3 &amp; <a href="https://vuefire.vuejs.org/">VueFire</a>.</p><p>I put a lot of effort into this weekly newsletter, and you can support my work in the following ways:</p><ul><li>Reply to this mail with a short testimonial about why you love this newsletter. I will reference it at <a href="https://weekly-vue.news?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">weekly-vue.news</a>.</li><li>Share <a href="https://weekly-vue.news?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">weekly-vue.news</a> on social media and help me spread the word.</li><li><a href="https://www.buymeacoffee.com/mokkapps?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">Buy me a coffee</a> ☺️</li></ul><p>Have a great week ☀️</p><h3>Vue Tip: Dynamically Add &amp; Remove Route While App Is Running</h3><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FIOa8NjlEiGg%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DIOa8NjlEiGg&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FIOa8NjlEiGg%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/816dd1ecee644fe51c74fc5850c27442/href">https://medium.com/media/816dd1ecee644fe51c74fc5850c27442/href</a></iframe><p>Adding routes to your router is usually done via the routes option, but in some situations, you might want to add or remove routes while the application is already running.</p><p><a href="https://router.vuejs.org">Vue Router</a> provides two functions for dynamic routing: router.addRoute() and router.removeRoute()</p><h4><a href="https://mokkapps.de/vue-tips/dynamically-add-and-remove-route-while-app-is-running#adding-routes">Adding Routes</a></h4><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*0CHJpN7ZGkI04Tfg" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><p>addRoute<strong>only</strong> registers a new route. If you want to navigate to the newly added route, you need to <strong>manually navigate</strong> with router.push() or router.replace().</p><p>It’s also possible to add nested routes:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*I9t64INw5eeJGG7v" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><h4><a href="https://mokkapps.de/vue-tips/dynamically-add-and-remove-route-while-app-is-running#removing-routes">Removing Routes</a></h4><p>There are three ways to remove an existing route:</p><ul><li>Use router.removeRoute():</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*xL9IwI4c2xXlxoYE" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><ul><li>Use the callback returned by router.addRoute():</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*VLPWO2d1mnKBiuUG" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><ul><li>Add a route with a conflicting name. If you try to add a route with the same name as an existing route, it will remove the first route and add the new route:</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*qV7IdGNsCc7etGAV" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><p><a href="https://stackblitz.com/edit/vue-tip-add-route-while-app-is-running">StackBlitz Demo</a></p><p>Check the <a href="https://router.vuejs.org/guide/advanced/dynamic-routing.html#adding-routes">official documentation</a> for more details about this feature.</p><h3>Curated Vue Content</h3><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*sqEKCi2w1texX0KN" /></figure><p><a href="https://mokkapps.de/blog/create-a-table-of-contents-with-active-states-in-nuxt-3/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter"><strong>📕 Create a Table of Contents With Active States in Nuxt 3</strong></a><strong> — </strong><a href="https://mokkapps.de/blog/create-a-table-of-contents-with-active-states-in-nuxt-3/"><strong>mokkapps.de</strong></a></p><p>In this article, I will show you how to create a sticky table of contents sidebar with an active state based on the current scroll position using <a href="https://nuxt.com/">Nuxt 3</a>, <a href="https://nuxt.com/modules/content">Nuxt Content</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API">Intersection Observer</a>.</p><h4><a href="https://debbie.codes/blog/migrating-nuxt2-nuxt3/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Migrating from Nuxt 2 to Nuxt 3</a></h4><p><a href="https://debbie.codes/blog/migrating-nuxt2-nuxt3/">debbie.codes</a></p><p>👉🏻 Debbie shares with you the steps she took to migrate her site from Nuxt 2 to Nuxt 3.</p><h4><a href="https://medium.com/comsystoreply/nuxt-3-usefetch-reactive-vue-at-its-best-14729f6f5be7?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Nuxt 3 + useFetch = Reactive Vue at its best 🔥</a></h4><p><a href="https://medium.com/comsystoreply/nuxt-3-usefetch-reactive-vue-at-its-best-14729f6f5be7">medium.com</a></p><p>👉🏻 Vue utilizes reactive programming.</p><p>👉🏻 By using useFetch provided by Nuxt 3 we can get the most out of this programming paradigm and reduce code complexity.</p><h4><a href="https://dev.to/israelortuno/event-bus-pattern-in-nuxt-3-with-full-typescript-support-1okp?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Event Bus Pattern in Nuxt 3 with Full TypeScript Support</a></h4><p><a href="https://dev.to/israelortuno/event-bus-pattern-in-nuxt-3-with-full-typescript-support-1okp">dev.to</a></p><p>👉🏻 Using an Event Bus is an easy way to communicate different parts of our application.</p><p>👉🏻 In this article, Isreal learns us how to implement it with Nuxt 3 and TypeScript.</p><h3>Quote of the Week</h3><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*59gfpS7aXZ8AxgMn" /></figure><h3>JavaScript Tip: Measuring the perfomance of functions</h3><p><a href="https://youtube.com/shorts/MSRfR2RYneE">JavaScript Tip: Measuring the performance of functions</a></p><p>We can use the Performance Web API to check the execution time of our code.</p><p>The <a href="https://developer.mozilla.org/en-US/docs/Web/API/Performance/now">performance.now</a> function returns the value of time in milliseconds.</p><p>The returned value represents the time elapsed since the time origin. The time origin is a standard time which is considered to be the beginning of the current document’s lifetime.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*2p7oAueCGCw8eiv3" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><h3>Curated Web Development Content</h3><h4><a href="https://www.meziantou.net/misconceptions-about-date-and-time.htm?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 35 Misconceptions about date and time</a></h4><p><a href="https://www.meziantou.net/misconceptions-about-date-and-time.htm">www.meziantou.net</a></p><p>👉🏻 Everybody uses the same calendar.</p><p>👉🏻 1 year equals 12 months.</p><p>👉🏻 GMT is the same as UTC.</p><p>👉🏻 Time zone offsets are always integer numbers of hours.</p><p>👉🏻 Weeks start on Monday. And more.</p><h4><a href="https://angularexperts.io/blog/advanced-typescript/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Advanced TypeScript</a></h4><p><a href="https://angularexperts.io/blog/advanced-typescript/">angularexperts.io</a></p><p>Get familiar with some of Typescript’s greatest advanced features:</p><p>👉🏻 Union and intersection types</p><p>👉🏻 Keyof</p><p>👉🏻 Typeof</p><p>👉🏻 Conditional types</p><p>👉🏻 Utility types</p><p>👉🏻 Infer type</p><p>👉🏻 Mapped types</p><h4><a href="https://github.com/microsoft/TypeScript/pull/51387?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Converting the TypeScript Codebase to Modules</a></h4><p><a href="https://github.com/microsoft/TypeScript/pull/51387">github.com</a></p><p>👉🏻 The TypeScript team recently migrated the TypeScript codebase from legacy namespaces to ECMAScript modules.</p><p>👉🏻 It improved compiler performance by 10–25%.</p><h4><a href="https://profy.dev/article/javascript-data-structures?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Data Structures In Frontend JavaScript In The Real World</a></h4><p><a href="https://profy.dev/article/javascript-data-structures">profy.dev</a></p><p>👉🏻 You will see examples that you might recognize from your own code or that can use in your projects or on the job.</p><h4><a href="https://simonwillison.net/2022/Oct/29/the-perfect-commit/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 The Perfect Commit</a></h4><p><a href="https://simonwillison.net/2022/Oct/29/the-perfect-commit/">simonwillison.net</a></p><p>👉🏻 The perfect commit contains the implementation, tests to show the implementation works, updated documentation, and a link to an issue thread providing further context.</p><h4><a href="https://github.com/hartwork/git-delete-merged-branches?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">🛠️ git-delete-merged-branches</a></h4><p><a href="https://github.com/hartwork/git-delete-merged-branches">github.com</a></p><p>👉🏻 A command-line tool for keeping repositories clean.</p><p>👉🏻 It supports deletion of both local and remote branches and workflows with multiple release branches.</p><h4><a href="https://icon.ray.so/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">🛠️ Icon Maker by Raycast</a></h4><p><a href="https://icon.ray.so/">icon.ray.so</a></p><p>👉🏻 A tool to create beautiful icons for your projects, apps, or Raycast extensions with ease.</p><h4><a href="https://kingsora.github.io/OverlayScrollbars/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">🛠️ OverlayScrollbars</a></h4><p><a href="https://kingsora.github.io/OverlayScrollbars/">kingsora.github.io</a></p><p>👉🏻 JS scrollbar plugin to replace native scrollbars</p><p>👉🏻 Provides custom styleable overlay scrollbars while keeping a native functionality and feel.</p><p>👉🏻 v2.0 is a full rewrite in TypeScript and smaller, too.</p><h3>Time to relax and destroy something</h3><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*d4Jpg72hFwTMfyMM" /></figure><p><a href="https://neal.fun/asteroid-launcher/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter"><strong>🛠️ Simulate an Asteroid Impact in Your Hometown</strong></a><strong> — </strong><a href="https://neal.fun/asteroid-launcher/"><strong>neal.fun</strong></a></p><p>👉🏻 Asteroid Launcher is a website that allows users to simulate how an asteroid might destroy any given locale.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5509a03ac23d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Create a Table of Contents With Active States in Nuxt 3]]></title>
            <link>https://mokkappsdev.medium.com/create-a-table-of-contents-with-active-states-in-nuxt-3-31ce5db4409d?source=rss-b6dc9bc6fff4------2</link>
            <guid isPermaLink="false">https://medium.com/p/31ce5db4409d</guid>
            <category><![CDATA[nuxt]]></category>
            <category><![CDATA[nuxtjs]]></category>
            <category><![CDATA[vuejs]]></category>
            <category><![CDATA[cto]]></category>
            <category><![CDATA[vue]]></category>
            <dc:creator><![CDATA[Michael Hoffmann]]></dc:creator>
            <pubDate>Thu, 08 Dec 2022 08:15:31 GMT</pubDate>
            <atom:updated>2022-12-08T08:15:31.963Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*y40WGG8zByij6SSp.jpg" /></figure><p>I’m a big fan of a table of contents (ToC) on the side of a blog post page, especially if it is a long article. It helps me gauge the article’s length and allows me to navigate between the sections quickly.</p><p>In this article, I will show you how to create a sticky table of contents sidebar with an active state based on the current scroll position using <a href="https://nuxt.com/">Nuxt 3</a>, <a href="https://nuxt.com/modules/content">Nuxt Content</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API">Intersection Observer</a>.</p><h3>Demo</h3><p>The following StackBlitz contains the source code that is used in the following chapters:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fstackblitz.com%2Fedit%2Fnuxt-content-table-of-contents-demo%3Fembed%3D1%26file%3DREADME.md&amp;display_name=StackBlitz&amp;url=https%3A%2F%2Fstackblitz.com%2Fedit%2Fnuxt-content-table-of-contents-demo%3Fembed%3D1%26file%3DREADME.md&amp;image=https%3A%2F%2Fsocial-img.staticblitz.com%2Fprojects%2Fnuxt-content-table-of-contents-demo%2F4ecd299bd2b7ada23385f9bbe37c1819&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=stackblitz" width="745" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/22d20907126f688dbf6e9054d617a3a8/href">https://medium.com/media/22d20907126f688dbf6e9054d617a3a8/href</a></iframe><h3>Setup</h3><p>For this demo, we need to <a href="https://nuxt.com/docs/getting-started/installation">initialize a Nuxt 3</a> project and install the <a href="https://content.nuxtjs.org/get-started">Nuxt Content</a> and <a href="https://tailwindcss.nuxt.dev/getting-started/setup">Nuxt Tailwind</a> (optional) modules.</p><p>We need to add these modules to nuxt.config.ts:</p><pre>export default defineNuxtConfig({<br>  modules: [&#39;@nuxt/content&#39;, &#39;@nuxtjs/tailwindcss&#39;],<br>})</pre><p>Of course, we need some content to show the table of contents. For this demo, I will reference the index.md file from my <a href="https://stackblitz.com/edit/nuxt-content-table-of-contents-demo?file=content/index.md">StackBlitz demo</a>.</p><p>To render this content, let’s create a <a href="https://nuxt.com/docs/guide/directory-structure/pages#catch-all-route">catch-all route</a> in the pages directory:</p><pre>&lt;template&gt;<br>  &lt;main class=&quot;p-4 flex flex-col gap-4&quot;&gt;<br>    &lt;ContentDoc&gt;<br>      &lt;template #default=&quot;{ doc }&quot;&gt;<br>        &lt;div class=&quot;grid grid-cols-12 gap-8&quot;&gt;<br>          &lt;div class=&quot;nuxt-content col-span-8&quot;&gt;<br>            &lt;ContentRenderer ref=&quot;nuxtContent&quot; :value=&quot;doc&quot; /&gt;<br>          &lt;/div&gt;<br>        &lt;/div&gt;<br>      &lt;/template&gt;<br>    &lt;/ContentDoc&gt;<br>  &lt;/main&gt;<br>&lt;/template&gt;</pre><p>The &lt;ContentDoc&gt; component fetches and renders a single document, and the &lt;ContentRenderer&gt; component renders the body of a Markdown document.</p><p><a href="https://content.nuxtjs.org/api/components/content-renderer">Check the official docs</a> for more information about these Nuxt Content components.</p><p>Now let’s add a TableOfContents.vue component to this template:</p><pre>&lt;script setup lang=&quot;ts&quot;&gt;<br>const activeTocId = ref(null)<br>&lt;/script&gt;<br><br>&lt;template&gt;<br>  &lt;main class=&quot;p-4 flex flex-col gap-4&quot;&gt;<br>    &lt;ContentDoc&gt;<br>      &lt;template #default=&quot;{ doc }&quot;&gt;<br>        &lt;div class=&quot;grid grid-cols-12 gap-8&quot;&gt;<br>          &lt;div class=&quot;nuxt-content col-span-8&quot;&gt;<br>            &lt;ContentRenderer ref=&quot;nuxtContent&quot; :value=&quot;doc&quot; /&gt;<br>          &lt;/div&gt;<br>          &lt;div class=&quot;col-span-4 border rounded-md p-4&quot;&gt;<br>            &lt;div class=&quot;sticky top-0 flex flex-col items-center&quot;&gt;<br>              &lt;TableOfContents :activeTocId=&quot;activeTocId&quot; /&gt;<br>            &lt;/div&gt;<br>          &lt;/div&gt;<br>        &lt;/div&gt;<br>      &lt;/template&gt;<br>    &lt;/ContentDoc&gt;<br>  &lt;/main&gt;<br>&lt;/template&gt;</pre><p>I’ll explain the activeTocId prop in the following &quot;Intersection Observer&quot; chapter.</p><p>Let’s take a look at the component’s code:</p><pre>&lt;script setup lang=&quot;ts&quot;&gt;<br>import { Ref } from &#39;vue&#39;<br><br>const props = withDefaults(defineProps&lt;{ activeTocId: string }&gt;(), {})<br><br>const router = useRouter()<br><br>const { data: blogPost } = await useAsyncData(`blogToc`, () =&gt; queryContent(`/`).findOne())<br>const tocLinks = computed(() =&gt; blogPost.value?.body.toc.links ?? [])<br><br>const onClick = (id: string) =&gt; {<br>  const el = document.getElementById(id)<br>  if (el) {<br>    router.push({ hash: `#${id}` })<br>    el.scrollIntoView({ behavior: &#39;smooth&#39;, block: &#39;center&#39; })<br>  }<br>}<br>&lt;/script&gt;<br><br>&lt;template&gt;<br>  &lt;div class=&quot;max-h-82 overflow-auto&quot;&gt;<br>    &lt;h4&gt;Table of Contents&lt;/h4&gt;<br>    &lt;nav class=&quot;flex mt-4&quot;&gt;<br>      &lt;ul class=&quot;ml-0 pl-4&quot;&gt;<br>        &lt;li<br>          v-for=&quot;{ id, text, children } in tocLinks&quot;<br>          :id=&quot;`toc-${id}`&quot;<br>          :key=&quot;id&quot;<br>          class=&quot;cursor-pointer text-sm list-none ml-0 mb-2 last:mb-0&quot;<br>          @click=&quot;onClick(id)&quot;<br>        &gt;<br>          {{ text }}<br>          &lt;ul v-if=&quot;children&quot; class=&quot;ml-3 my-2&quot;&gt;<br>            &lt;li<br>              v-for=&quot;{ id: childId, text: childText } in children&quot;<br>              :id=&quot;`toc-${childId}`&quot;<br>              :key=&quot;childId&quot;<br>              class=&quot;cursor-pointer text-xs list-none ml-0 mb-2 last:mb-0&quot;<br>              @click.stop=&quot;onClick(childId)&quot;<br>            &gt;<br>              {{ childText }}<br>            &lt;/li&gt;<br>          &lt;/ul&gt;<br>        &lt;/li&gt;<br>      &lt;/ul&gt;<br>    &lt;/nav&gt;<br>  &lt;/div&gt;<br>&lt;/template&gt;</pre><p>Let’s analyze this code:</p><p>To get a list of all available headlines, we use the <a href="https://content.nuxtjs.org/api/composables/query-content">queryContent composable</a> and access them via body.toc.links:</p><pre>const { data: blogPost } = await useAsyncData(`blogToc`, () =&gt; queryContent(`/`).findOne())<br>const tocLinks = computed(() =&gt; blogPost.value?.body.toc.links ?? [])</pre><p>If someone clicks on a link in the ToC, we query the HTML element from the DOM, push the hash route and smoothly scroll the element into the viewport:</p><pre>const onClick = (id: string) =&gt; {<br>  const el = document.getElementById(id)<br>  if (el) {<br>    router.push({ hash: `#${id}` })<br>    el.scrollIntoView({ behavior: &#39;smooth&#39;, block: &#39;center&#39; })<br>  }<br>}</pre><p>At this point, we can show a list of all the headlines of our content in the sidebar, but our ToC does not indicate which headline is currently visible.</p><h3>Intersection Observer</h3><p>We use the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API">Intersection Observer</a> to handle detecting when an element scrolls into our viewport. It’s <a href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#browser_compatibility">supported by almost every browser</a>.</p><p>Nuxt Content automatically adds an id to each heading of our content files. Using document.querySelectorAll, we query all h2 and h3 elements associated with an id and use the Intersection Observer API to get informed when they scroll into view.</p><p>Let’s go ahead and implement that logic:</p><pre>&lt;script setup lang=&quot;ts&quot;&gt;<br>import { watchDebounced } from &#39;@vueuse/core&#39;<br><br>const activeTocId = ref(null)<br>const nuxtContent = ref(null)<br><br>const observer: Ref&lt;IntersectionObserver | null | undefined&gt; = ref(null)<br>const observerOptions = reactive({<br>  root: nuxtContent.value,<br>  threshold: 0.5,<br>})<br><br>onMounted(() =&gt; {<br>  observer.value = new IntersectionObserver((entries) =&gt; {<br>    entries.forEach((entry) =&gt; {<br>      const id = entry.target.getAttribute(&#39;id&#39;)<br>      if (entry.isIntersecting) {<br>        activeTocId.value = id<br>      }<br>    })<br>  }, observerOptions)<br><br>  document.querySelectorAll(&#39;.nuxt-content h2[id], .nuxt-content h3[id]&#39;).forEach((section) =&gt; {<br>    observer.value?.observe(section)<br>  })<br>})<br><br>onUnmounted(() =&gt; {<br>  observer.value?.disconnect()<br>})<br>&lt;/script&gt;</pre><p>Let’s break down the single steps that are happening in this code.</p><p>First, we define some reactive variables:</p><ul><li>activeTocId is used to track the currently active DOM element to be able to add some CSS styles to it.</li><li>nuxtContent is a <a href="https://vuejs.org/guide/essentials/template-refs.html#template-refs">Template Ref</a> to access the DOM element of the ContentRenderer component.</li><li>observer is used to track the h2 and h3 HTML elements that scroll into the viewport.</li><li>observerOptions contains a set of options that define when the observer callback is invoked. It contains the nuxtContent ref as root for the observer and a threshold of 0.5, which means that if 50% of the way through the viewport is visible, the callback will fire. You can also set it to 0; it will fire the callback if one element pixel is visible.</li></ul><p>In the onMounted lifecycle hook, we are initializing the observer. We iterate over each article heading and set the activeTocId value if the entry intersects with the viewport. We also use document.querySelectorAll to target our .nuxt-content article and get the DOM elements that are either h2 or h3 elements with IDs and observe those using our previously initialized IntersectionObserver.</p><p>Finally, we are disconnecting our observer in the onUnmounted lifecycle hook to inform the observer to no longer track these headings when we navigate away.</p><h3>Style Active Link</h3><p>Let’s improve the code by applying styles to the activeTocId element in our table of contents component. It should be highlighted and show an indicator:</p><pre>&lt;script setup lang=&quot;ts&quot;&gt;<br>import { watchDebounced } from &#39;@vueuse/core&#39;<br>import { Ref } from &#39;vue&#39;<br><br>const props = withDefaults(defineProps&lt;{ activeTocId: string }&gt;(), {})<br><br>const router = useRouter()<br><br>const sliderHeight = useState(&#39;sliderHeight&#39;, () =&gt; 0)<br>const sliderTop = useState(&#39;sliderTop&#39;, () =&gt; 0)<br>const tocLinksH2: Ref&lt;Array&lt;HTMLElement&gt;&gt; = ref([])<br>const tocLinksH3: Ref&lt;Array&lt;HTMLElement&gt;&gt; = ref([])<br><br>const { data: blogPost } = await useAsyncData(`blogToc`, () =&gt; queryContent(`/`).findOne())<br>const tocLinks = computed(() =&gt; blogPost.value?.body.toc.links ?? [])<br><br>const onClick = (id: string) =&gt; {<br>  const el = document.getElementById(id)<br>  if (el) {<br>    router.push({ hash: `#${id}` })<br>    el.scrollIntoView({ behavior: &#39;smooth&#39;, block: &#39;center&#39; })<br>  }<br>}<br><br>watchDebounced(<br>  () =&gt; props.activeTocId,<br>  (newActiveTocId) =&gt; {<br>    const h2Link = tocLinksH2.value.find((el: HTMLElement) =&gt; el.id === `toc-${newActiveTocId}`)<br>    const h3Link = tocLinksH3.value.find((el: HTMLElement) =&gt; el.id === `toc-${newActiveTocId}`)<br><br>    if (h2Link) {<br>      sliderHeight.value = h2Link.offsetHeight<br>      sliderTop.value = h2Link.offsetTop - 100<br>    } else if (h3Link) {<br>      sliderHeight.value = h3Link.offsetHeight<br>      sliderTop.value = h3Link.offsetTop - 100<br>    }<br>  },<br>  { debounce: 200, immediate: true }<br>)<br>&lt;/script&gt;<br><br>&lt;template&gt;<br>  &lt;div class=&quot;max-h-82 overflow-auto&quot;&gt;<br>    &lt;h4&gt;Table of Contents&lt;/h4&gt;<br>    &lt;nav class=&quot;flex mt-4&quot;&gt;<br>      &lt;div class=&quot;relative bg-secondary w-0.5 overflow-hidden rounded&quot;&gt;<br>        &lt;div<br>          class=&quot;<br>            absolute<br>            left-0<br>            w-full<br>            transition-all<br>            duration-200<br>            rounded<br>            bg-red-500<br>          &quot;<br>          :style=&quot;{ height: `${sliderHeight}px`, top: `${sliderTop}px` }&quot;<br>        &gt;&lt;/div&gt;<br>      &lt;/div&gt;<br>      &lt;ul class=&quot;ml-0 pl-4&quot;&gt;<br>        &lt;li<br>          v-for=&quot;{ id, text, children } in tocLinks&quot;<br>          :id=&quot;`toc-${id}`&quot;<br>          :key=&quot;id&quot;<br>          ref=&quot;tocLinksH2&quot;<br>          class=&quot;cursor-pointer text-sm list-none ml-0 mb-2 last:mb-0&quot;<br>          :class=&quot;{ &#39;font-bold&#39;: id === activeTocId }&quot;<br>          @click=&quot;onClick(id)&quot;<br>        &gt;<br>          {{ text }}<br>          &lt;ul v-if=&quot;children&quot; class=&quot;ml-3 my-2&quot;&gt;<br>            &lt;li<br>              v-for=&quot;{ id: childId, text: childText } in children&quot;<br>              :id=&quot;`toc-${childId}`&quot;<br>              :key=&quot;childId&quot;<br>              ref=&quot;tocLinksH3&quot;<br>              class=&quot;cursor-pointer text-xs list-none ml-0 mb-2 last:mb-0&quot;<br>              :class=&quot;{ &#39;font-bold&#39;: childId === activeTocId }&quot;<br>              @click.stop=&quot;onClick(childId)&quot;<br>            &gt;<br>              {{ childText }}<br>            &lt;/li&gt;<br>          &lt;/ul&gt;<br>        &lt;/li&gt;<br>      &lt;/ul&gt;<br>    &lt;/nav&gt;<br>  &lt;/div&gt;<br>&lt;/template&gt;</pre><p>We use the <a href="https://vueuse.org/shared/watchdebounced/#watchdebounced">VueUse’s watchDebounced composable</a> to debounced watch changes of the active ToC element ID:</p><pre>watchDebounced(<br>  () =&gt; props.activeTocId,<br>  (newActiveTocId) =&gt; {<br>    const h2Link = tocLinksH2.value.find((el: HTMLElement) =&gt; el.id === `toc-${newActiveTocId}`)<br>    const h3Link = tocLinksH3.value.find((el: HTMLElement) =&gt; el.id === `toc-${newActiveTocId}`)<br><br>    if (h2Link) {<br>      sliderHeight.value = h2Link.offsetHeight<br>      sliderTop.value = h2Link.offsetTop - 100<br>    } else if (h3Link) {<br>      sliderHeight.value = h3Link.offsetHeight<br>      sliderTop.value = h3Link.offsetTop - 100<br>    }<br>  },<br>  { debounce: 200, immediate: true }<br>)</pre><p>Based on the current active ToC element ID, we find the HTML element from the list of available links and set the slider height &amp; top values accordingly.</p><p>Check the <a href="https://mokkapps.de/blog/create-a-table-of-contents-with-active-states-in-nuxt-3#demo">StackBlitz demo</a> for the full source code and to play around with this implementation. A similar ToC is also available on my <a href="https://mokkapps.de/blog">blog</a>.</p><h3>Conclusion</h3><p>I’m pleased with my table of contents implementation using Nuxt 3, Nuxt Content, and Intersection Observer.</p><p>Of course, you can use the Intersection Observer in a traditional Vue application without Nuxt. The Intersection Observer API is mighty and can also be used to implement features like <a href="https://www.webtips.dev/how-to-lazy-load-images-with-intersection-observer">lazy-loading images</a>.</p><p>Leave a comment if you have a better solution to implement such a ToC.</p><p>If you liked this article, follow me on <a href="https://twitter.com/mokkapps">Twitter</a> to get notified about new blog posts and more content from me.</p><p>Alternatively (or additionally), you can also <a href="https://mokkapps.de/newsletter">subscribe to my newsletter</a>.</p><p><em>Originally published at </em><a href="https://mokkapps.de/blog/create-a-table-of-contents-with-active-states-in-nuxt-3/"><em>https://mokkapps.de</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=31ce5db4409d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Weekly Vue News — #70 — Force-Enable Vue Devtools in Production Build]]></title>
            <link>https://mokkappsdev.medium.com/weekly-vue-news-70-force-enable-vue-devtools-in-production-build-d35576c30bff?source=rss-b6dc9bc6fff4------2</link>
            <guid isPermaLink="false">https://medium.com/p/d35576c30bff</guid>
            <category><![CDATA[vue]]></category>
            <category><![CDATA[vuejs]]></category>
            <category><![CDATA[nuxt]]></category>
            <dc:creator><![CDATA[Michael Hoffmann]]></dc:creator>
            <pubDate>Tue, 06 Dec 2022 07:20:36 GMT</pubDate>
            <atom:updated>2022-12-06T07:20:36.058Z</atom:updated>
            <content:encoded><![CDATA[<h3>Weekly Vue News — #70 — Force-Enable Vue Devtools in Production Build</h3><p>Hi 👋</p><p>My plans for this week are creating new video content for my brand-new <a href="https://youtube.com/@mokkapps">YouTube channel</a>.</p><p>I tried many different screencast tools but finally decided to buy <a href="https://www.telestream.net/screenflow/overview.htm">Screenflow</a> which is a very powerful tool.</p><p>Have a great week ☀️</p><h3>Vue Tip: Force-Enable Vue Devtools in Production Build</h3><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2F5yfRyQsOOI0%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D5yfRyQsOOI0&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2F5yfRyQsOOI0%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/d8fa266a79ed6bc7120d1fb35c28c20c/href">https://medium.com/media/d8fa266a79ed6bc7120d1fb35c28c20c/href</a></iframe><p>Often we cannot reproduce a bug in the development environment and need to debug it in production.</p><p>Unfortunately, in most cases, the <a href="https://devtools.vuejs.org/">Vue Devtools browser extension</a> is disabled in production builds:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*BQiZBQrNO6bvsely" /></figure><p>Luckily, there is a way to <strong>force-enable</strong> it in production builds.</p><h4><a href="https://mokkapps.de/vue-tips/force-enable-vue-devtools-in-production-build#open-console-in-browser-devtools">Open Console in Browser DevTools</a></h4><p>First, we need to open the console in your browser’s DevTools:</p><p>Windows or Linux: Ctrl + Shift + J</p><p>Mac: Cmd + Option + J</p><h4><a href="https://mokkapps.de/vue-tips/force-enable-vue-devtools-in-production-build#access-vue-app-instance">Access Vue App Instance</a></h4><p>Now we need to get access to the Vue app instance:</p><p>If you are using <strong>Vue 2</strong> you need to call:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*oRZZqmWh9YhDVq1P" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><p>For Vue 3, you need to run the following code in the console:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*MC_EvvDqfwiJN6Wu" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><p>The app variable contains a reference to the Vue app instance:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*AlPnnk9P1h4t2MF2" /></figure><p>We can now store the app version in a new variable called version:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*S3F_0XtAW4xcFHPc" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><h4><a href="https://mokkapps.de/vue-tips/force-enable-vue-devtools-in-production-build#access-vue-devtools-instance">Access Vue Devtools Instance</a></h4><p>In the next step, we need access to the Vue Devtools instance which is available via window.__VUE_DEVTOOLS_GLOBAL_HOOK__:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*qMkPpEbiKX0JSFg2" /></figure><p>We store it in a variable called devtools and set its property enabled to true:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*b83KP4Eg8b_3LpRp" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><p>Finally, we need to re-initialize the Vue app instance:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*hAXIoCkSoaD1tEsO" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><p>The last step is to refresh the browser DevTools to be able to detect the changes on the Vue app instance:</p><p>Windows or Linux: Alt + R</p><p>Mac: Option + R</p><p>Now the Vue Devtools extension is enabled in the production build:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*6tMvMcCMkNTqwOhn" /></figure><p>ℹ️ If you don’t want to do this on your own, check the <a href="https://chrome.google.com/webstore/detail/vue-force-dev/oohfffedbkbjnbpbbedapppafmlnccmb/related">“Vue force dev” Chrome extension</a></p><h3>Curated Vue Content</h3><h4><a href="https://www.smashingmagazine.com/2022/11/optimizing-vue-app/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Optimizing A Vue App</a></h4><p><a href="https://www.smashingmagazine.com/2022/11/optimizing-vue-app/">www.smashingmagazine.com</a></p><p>👉🏻 In this article, Michelle Barker will walk you through some of the front-end optimization tips to keep our Vue apps as efficient as possible.</p><h4><a href="https://firebase.blog/posts/2022/11/investing-in-vuefire-nuxt-vue?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Investing in Vue, Nuxt, and VueFire</a></h4><p><a href="https://firebase.blog/posts/2022/11/investing-in-vuefire-nuxt-vue">firebase.blog</a></p><p>👉🏻 Google’s Firebase platform is building a ‘first class’ experience for Vue developers, including support for Nuxt.</p><h4><a href="https://medium.com/bauer-kirch/a-domain-driven-vue-js-architecture-77771c20f0da?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 A domain-driven Vue.js Architecture</a></h4><p><a href="https://medium.com/bauer-kirch/a-domain-driven-vue-js-architecture-77771c20f0da">medium.com</a></p><p>👉🏻 “For our reasonably large enterprise Vue.js app, this approach helped us a lot in clarifying responsibilities and enforcing separation of concerns on an architectural level. “</p><h4><a href="https://github.com/Tahul/pinceau?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">🛠️ pinceau</a></h4><p><a href="https://github.com/Tahul/pinceau">github.com</a></p><p>👉🏻 A CSS-in-TypeScript framework built for Vue</p><p>👉🏻 Still early days but has the perk of seamless integration into Vue, and works with Nuxt, Vitesse, and Vite.</p><h3>Quote of the Week</h3><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*fsw9VjN0gpS20bkX" /></figure><h3>JavaScript Tip: Clean up promises similarly to a try/catch/finally block</h3><p>The <strong>finally()</strong> method of a <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise</a> schedules a function, the <em>callback function</em>, to be called when the promise is settled (fullfilled or rejected).</p><p><strong>It’s very convienient for cleaning up similarly to try/catch/finally blocks.</strong></p><p>Like then() and catch(), it immediately returns an equivalent <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise</a> object, allowing you to chain calls to another promise method, an operation called <em>composition</em>.</p><p>This lets you avoid duplicating code in both the promise’s <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">then()</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch">catch()</a> handlers.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*Rs5Dv9bkotdUvVHX" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><h3>Curated Web Development Content</h3><h4><a href="https://www.totaltypescript.com/tutorials/zod?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Zod Tutorial</a></h4><p><a href="https://www.totaltypescript.com/tutorials/zod">www.totaltypescript.com</a></p><p>👉🏻 How to use the schema validation library Zod to check types at runtime.</p><p>👉🏻 Explained by none other than the excellent Matt Pocock.ypeScript-first schema declaration and validation library. In this tutorial, Matt Pocock has prepared a set of exercises that will help you level up.</p><h4><a href="https://www.joshwcomeau.com/css/interactive-guide-to-flexbox/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 An Interactive Guide to Flexbox</a></h4><p><a href="https://www.joshwcomeau.com/css/interactive-guide-to-flexbox/">www.joshwcomeau.com</a></p><p>👉🏻 A new, interactive explainer from Josh, with over 20 demos showing off how Flexbox works.</p><h4><a href="https://github.com/eslint/eslint/discussions/16557?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Complete rewrite of ESLint</a></h4><p><a href="https://github.com/eslint/eslint/discussions/16557">github.com</a></p><p>👉🏻 ESLint is joining forces with TSLint and planning a complete rewrite to prepare for “the next ten years of linting.”</p><h4><a href="https://www.smashingmagazine.com/2022/10/futuristic-css/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Futuristic CSS</a></h4><p><a href="https://www.smashingmagazine.com/2022/10/futuristic-css/">www.smashingmagazine.com</a></p><p>👉🏻 Future CSS trends and takes a look at some far-fetched and futuristic CSS features that might one day make their way to the browses, such as CSS toggles, switch function, intrinsic typography. And more.</p><h4><a href="https://www.youtube.com/watch?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter&amp;v=u6QwiJM_TUo">📹 You are not your user</a></h4><p><a href="https://www.youtube.com/watch?v=u6QwiJM_TUo">www.youtube.com</a></p><p>👉🏻 This is a great, quick explainer on the importance of including everyone from the beginning of your project to ensure accessible outcomes.</p><h4><a href="https://github.com/sindresorhus/trash-cli?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">🛠️ trash-cli</a></h4><p><a href="https://github.com/sindresorhus/trash-cli">github.com</a></p><p>👉🏻 Stop using rm -rf to delete files on your computer.</p><p>👉🏻 In contrast to rm which is dangerous and permanently deletes files, this only moves them to the trash, which is much safer and reversible.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d35576c30bff" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Weekly Vue News — #69 — Use Provide & Inject to Avoid Prop Drilling]]></title>
            <link>https://mokkappsdev.medium.com/weekly-vue-news-69-use-provide-inject-to-avoid-prop-drilling-e46f66edd3f2?source=rss-b6dc9bc6fff4------2</link>
            <guid isPermaLink="false">https://medium.com/p/e46f66edd3f2</guid>
            <category><![CDATA[newsletter]]></category>
            <category><![CDATA[vue]]></category>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[vuejs]]></category>
            <dc:creator><![CDATA[Michael Hoffmann]]></dc:creator>
            <pubDate>Mon, 28 Nov 2022 14:35:34 GMT</pubDate>
            <atom:updated>2022-11-28T14:35:34.081Z</atom:updated>
            <content:encoded><![CDATA[<h3>Weekly Vue News — #69 — Use Provide &amp; Inject to Avoid Prop Drilling</h3><p>Hi 👋</p><p>I’m still experimenting with my quick-tip videos; creating these videos is a lot of fun. You can find them on my social media profiles (<a href="https://twitter.com/mokkapps">Twitter</a>, <a href="https://www.linkedin.com/in/mokkapps">LinkedIn</a>, <a href="https://instagram.com/mokkapps">Instagram</a>).</p><p>I put a lot of effort into this weekly newsletter, and you can support my work in the following ways:</p><ul><li>Reply to this mail with a short testimonial about why you love this newsletter. I will reference it at <a href="https://weekly-vue.news">weekly-vue.news</a>.</li><li>Share <a href="https://weekly-vue.news">weekly-vue.news</a> on social media and help me spread the word.</li><li><a href="https://www.buymeacoffee.com/mokkapps">Buy me a coffee</a> ☺️</li></ul><p>Have a great week ☀️</p><h3>Vue Tip: Use Provide &amp; Inject to Avoid Prop Drilling</h3><p>Props are the standard way to pass data from the parent to a child component.</p><p>This works well in simple scenarios but has some drawbacks if a deeply nested component needs data from a distant ancestor component:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*py-YLM7tf-WcECaI" /></figure><p>Take a look at the &lt;Footer&gt; component: It needs to declare and pass the props to the &lt;DeepChild&gt; component, even if it does not care about them. Imagine a longer component chain between the parent and the deep child component; all would be affected along the way. This is called <strong>&quot;prop drilling&quot;</strong> and is no fun for us developers.</p><p>Usually, we solve this problem by using state management solutions like <a href="https://pinia.vuejs.org/">Pinia</a>.</p><p>But sometimes, we want to share data from a parent component to all its children components without using a store. If you are using Vue 2, you must either use a state management solution or pass the props down to the deeply nested component.</p><p>Vue 3 introduced a new concept to solve prop drilling with provide and inject :</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*pXxM76bLY50CSQ9Q" /></figure><p>The principle is simple:</p><ul><li>In the parent component, we declare the variables (props, data, computed, …), which will be accessible to all descendants via the <strong>provide</strong> key.</li><li>From any child component, we specify the list of injectable variables via the <strong>inject</strong> key</li></ul><h4><a href="http://localhost:3000/vue-tips/use-provide-inject-to-avoid-prop-drilling#provide"><strong>Provide</strong></a></h4><ul><li>To provide data to a component’s descendants, we use the provide() function:</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*gnIRdjcXiRPvy_hP" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><p>The first argument of the provide() function is the <strong>injection key</strong>, which can be a string or a Symbol. The descendant component uses this key to look up the desired value to inject. The second argument is the value, which can be of any type, including reactive state such as refs. Using reactive values in the provide() function establishes a reactive connection to the descendant component that injects the value.</p><p>As you can see in the above example, it is valid to call provide multiple times with different injection keys and values.</p><h4><a href="http://localhost:3000/vue-tips/use-provide-inject-to-avoid-prop-drilling#inject"><strong>Inject</strong></a></h4><p>To inject data provided by an ancestor component, we use the inject() function:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*-NuuWWUV-dlPeboy" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><p>For more details, check the <a href="https://vuejs.org/guide/components/provide-inject.html">official docs</a>.</p><h3>Curated Vue Content</h3><h4><a href="https://masteringnuxt.com/blog/nuxt-3-client-side-error-handling?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Nuxt 3 Client-Side Error Handling</a></h4><p><a href="https://masteringnuxt.com/blog/nuxt-3-client-side-error-handling">masteringnuxt.com</a></p><p>👉🏻 Michael explains the NuxtErrorBoundary component that comes with Nuxt 3.</p><p>👉🏻 It makes handling client-side errors a breeze.</p><h4><a href="https://www.simplethread.com/comment-threads-with-recursive-components-in-vue-3/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Comment Threads with Recursive Components in Vue 3</a></h4><p><a href="https://www.simplethread.com/comment-threads-with-recursive-components-in-vue-3/">www.simplethread.com</a></p><p>👉🏻 It’s common for applications to use threaded comment replies for managing communication.</p><p>👉🏻 In Vue, we can use recursion to help manage displaying those threads.</p><h3>TypeScript Tip: Make every property of a certain type required</h3><p>Required&lt;Type&gt; constructs a type consisting of all properties of Type set to required:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*3549Vqt4AV1Nnv2c" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><p>It’s the opposite of <a href="https://www.typescriptlang.org/docs/handbook/utility-types.html#partialtype">Partial</a>.</p><h3>Quote of the Week</h3><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*iL1f1L64RcP1Hj_4" /></figure><h3>Curated Web Development Content</h3><h4><a href="https://javascript.plainenglish.io/clean-code-in-typescript-a183d43f3bf0?gi=1b06474e0408&amp;utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Clean Code in TypeScript</a></h4><p><a href="https://javascript.plainenglish.io/clean-code-in-typescript-a183d43f3bf0?gi=1b06474e0408">javascript.plainenglish.io</a></p><p>👉🏻 Don’t add unneeded context</p><p>👉🏻 Use enum</p><p>👉🏻 Function names should say what they do</p><p>👉🏻 Prefer functional programming over imperative programming</p><p>👉🏻 Avoid negative conditionals</p><p>👉🏻 and more…</p><h4><a href="https://www.robinwieruch.de/typescript-node/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Using TypeScript with Node.js</a></h4><p><a href="https://www.robinwieruch.de/typescript-node/">www.robinwieruch.de</a></p><p>👉🏻 This tutorial is part 2 of 3 of a series.</p><p>👉🏻 It shows how to we migrating a Node.js project to TypeScript.</p><h4><a href="https://frontendmastery.com/posts/the-evolution-of-scalable-css/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 The Evolution Of Scalable CSS</a></h4><p><a href="https://frontendmastery.com/posts/the-evolution-of-scalable-css/">frontendmastery.com</a></p><p>👉🏻 “In this post, we’ll develop a deeper understanding of CSS by diving into the underlying issues that make it difficult to scale.”</p><h4><a href="https://rogovoy.me/blog/no-architecture?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 No architecture is better than bad architecture</a></h4><p><a href="https://rogovoy.me/blog/no-architecture">rogovoy.me</a></p><p>👉🏻 Building a solid architecture can be a waste of energy and can stop teams from working fast.</p><h4><a href="https://fasterthanli.me/articles/the-http-crash-course-nobody-asked-for?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 The HTTP crash course nobody asked for</a></h4><p><a href="https://fasterthanli.me/articles/the-http-crash-course-nobody-asked-for">fasterthanli.me</a></p><p>👉🏻 “The inner workings of HTTP/2 were intimidating and mysterious before I wrote this article, and now they feel somewhat approachable.”</p><h4><a href="https://github.com/markmead/hyperui?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">🛠️ HyperUI</a></h4><p><a href="https://github.com/markmead/hyperui">github.com</a></p><p>👉🏻 A collection of free Tailwind CSS components that can be used in your next project.</p><h4><a href="https://github.com/marcj/TypeRunner?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">🛠️ TypeRunner</a></h4><p><a href="https://github.com/marcj/TypeRunner">github.com</a></p><p>👉🏻 A TypeScript compiler that can do type checking up to 1000x faster and claims to “bring TypeScript to the next level.”</p><h4><a href="https://github.com/bencoveney/barrelsby?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">🛠️ Barrelsby</a></h4><p><a href="https://github.com/bencoveney/barrelsby">github.com</a></p><p>👉🏻 Automatically create TypeScript barrels for your entire code base.</p><p>👉🏻 Barrels help to simplify large blocks of import statements at the top of files and help to group up related functionality.</p><h4><a href="https://passwordpurgatory.com/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">😂 Password Purgatory</a></h4><p><a href="https://passwordpurgatory.com/">passwordpurgatory.com</a></p><p>👉🏻 “an intentionally infuriating API to request inane and ultimately unachievable password criteria intended to deliberately frustrate the user.”</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e46f66edd3f2" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Weekly Vue News — #68 — Change the Interpolation Delimiter]]></title>
            <link>https://mokkappsdev.medium.com/weekly-vue-news-68-change-the-interpolation-delimiter-32495e502531?source=rss-b6dc9bc6fff4------2</link>
            <guid isPermaLink="false">https://medium.com/p/32495e502531</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[newsletter]]></category>
            <category><![CDATA[vuejs]]></category>
            <category><![CDATA[vue]]></category>
            <dc:creator><![CDATA[Michael Hoffmann]]></dc:creator>
            <pubDate>Mon, 21 Nov 2022 17:13:04 GMT</pubDate>
            <atom:updated>2022-11-21T17:13:04.695Z</atom:updated>
            <content:encoded><![CDATA[<h3>Weekly Vue News — #68 — Change the Interpolation Delimiter</h3><p>Hi 👋</p><p>Since last week, Nuxt 3 is finally stable 🥳</p><p>I’m working on a new blog post about a ToC (Table of Contents) component for Nuxt Content v2.</p><p>Additionally, I’m experimenting with short video clips about my tips.</p><p>Here is an example: <a href="https://www.loom.com/share/0b00767197a64c79b4fa2c2ae0ac5f37">https://www.loom.com/share/0b00767197a64c79b4fa2c2ae0ac5f37</a></p><p>Let me know what you think about these kind of videos.</p><p>Have a great week ☀️</p><h3>Vue Tip: Change the Interpolation Delimiter</h3><p>It is possible to adjust the delimiters used for text interpolation within the template.</p><p><strong>This is typically used to avoid conflicting with server-side frameworks that also use mustache syntax.</strong></p><p>The default delimiters are the double curly braces (called mustache syntax): {{ }}</p><p>We can change the delimiter in the config object of the application instance:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*qSTd4jWEChWYnUVO" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><p>👉🏻 <a href="https://stackblitz.com/edit/vue-custom-delimiter?file=index.html">Try it out</a></p><p>⚠️ <strong>Important</strong></p><p>The compilerOptions config option is only respected when using the full build (i.e. the standalone vue.js that can compile templates in the browser).</p><p>If you are using the runtime-only build with a build setup, checkout <a href="https://vuejs.org/api/application.html#app-config-compileroptions">the official docs</a>.</p><h3>Curated Vue Content</h3><h4><a href="https://www.vuemastery.com/blog/nuxt-3-state-mangement-pinia-vs-usestate/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Nuxt 3 State Management: Pinia vs useState</a></h4><p><a href="https://www.vuemastery.com/blog/nuxt-3-state-mangement-pinia-vs-usestate/">www.vuemastery.com</a></p><p>👉🏻 In this article, Michael discusses the main differences between Pinia and useState and when to use each.</p><h4><a href="https://github.com/yyx990803/vite-vs-next-turbo-hmr/discussions/8?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Is Turbopack really 10x Faster than Vite?</a></h4><p><a href="https://github.com/yyx990803/vite-vs-next-turbo-hmr/discussions/8">github.com</a></p><p>👉🏻 Vue and Vite’s Evan You decided to run some benchmarks and ended up pretty deep down the rabbit hole.</p><h4><a href="https://tjk.github.io/vue-o2c/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">🛠️ Online Options API to Composition API converter for Vue</a></h4><p><a href="https://tjk.github.io/vue-o2c/">tjk.github.io</a></p><h3>JavaScript Tip: Manipulate URLs</h3><p>JavaScript has a built-in API that allows you to easily manipulate URLs and get their search parameters:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*xw9I1P7NG_p0joZl" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><h3>Curated Web Development Content</h3><h4><a href="https://tsh.io/state-of-frontend/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 The State of Frontend in 2022 survey</a></h4><p><a href="https://tsh.io/state-of-frontend/">tsh.io</a></p><p>👉🏻 “real day-to-day perspective from frontend professionals of all levels and backgrounds.”</p><p>👉🏻 I love to see Vue on the third place of used &amp; liked frameworks 💚</p><h4><a href="https://weizman.github.io/page-what-is-a-realm-in-js/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 What is a realm in JavaScript?</a></h4><p><a href="https://weizman.github.io/page-what-is-a-realm-in-js/">weizman.github.io</a></p><p>👉🏻 A realm is essentially the complete execution environment for a JavaScript program.</p><p>👉🏻 Interesting if you want to know how JavaScript works under the hood.</p><h4><a href="https://web.dev/state-of-css-2022/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 State of CSS 2022</a></h4><p><a href="https://web.dev/state-of-css-2022/">web.dev</a></p><p>👉🏻 This post is the article form of the State of CSS talk given at Google IO 2022.</p><p>👉🏻 It provides a brief overview of the new features and resources for more information.</p><h4><a href="https://www.freecodecamp.org/news/programming-in-typescript/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📹 Programming in TypeScript</a></h4><p><a href="https://www.freecodecamp.org/news/programming-in-typescript/">www.freecodecamp.org</a></p><p>👉🏻 5 hour YouTube course.</p><p>👉🏻 This beginner course will teach you everything you need to get started coding TypeScript.</p><h4><a href="https://marketplace.visualstudio.com/items?itemName=sburg.vscode-javascript-booster&amp;utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">🛠️ JavaScript Booster (VS Code Extension)</a></h4><p><a href="https://marketplace.visualstudio.com/items?itemName=sburg.vscode-javascript-booster">marketplace.visualstudio.com</a></p><p>👉🏻 Add quick actions to VS Code.</p><p>👉🏻 Useful for IntelliJ users who are used to these handy actions.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*a0F7YYTnihBEUZtn" /></figure><p><a href="https://jdan.github.io/98.css/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter"><strong>🛠️ 98.css</strong></a><strong> — </strong><a href="https://jdan.github.io/98.css/"><strong>jdan.github.io</strong></a></p><p>👉🏻 98.css is a CSS library for building interfaces that look like Windows 98</p><h3>Quote of the Week</h3><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*a54LSYqFmJDxonoE" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=32495e502531" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Weekly Vue News — #66 — Defining and Registering Vue Web Components]]></title>
            <link>https://mokkappsdev.medium.com/weekly-vue-news-66-defining-and-registering-vue-web-components-e7f7105518ff?source=rss-b6dc9bc6fff4------2</link>
            <guid isPermaLink="false">https://medium.com/p/e7f7105518ff</guid>
            <category><![CDATA[newsletter]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[vuejs]]></category>
            <category><![CDATA[vue]]></category>
            <dc:creator><![CDATA[Michael Hoffmann]]></dc:creator>
            <pubDate>Mon, 07 Nov 2022 14:12:07 GMT</pubDate>
            <atom:updated>2022-11-07T14:12:07.031Z</atom:updated>
            <content:encoded><![CDATA[<h3>Weekly Vue News — #66 — Defining and Registering Vue Web Components</h3><p>Hi 👋</p><p>I’m available for work from 9st January 2023, see tweet below.</p><p>This week I’ll work on a theme for <a href="https://sli.dev">Slidev</a>, an amazing tool for developers to create presentations.</p><p>Have a great week ☀️</p><h3>Vue Tip: Defining and Registering Vue Web Components</h3><p>Web Components is an umbrella term for a set of web native APIs that allows developers to create reusable custom elements. Vue has excellent support for both consuming and creating custom elements.</p><blockquote>The main advantage of web components is that they can be used with any framework or even without a framework.</blockquote><p>In three simple steps, let’s look at how we can create a web component from a Vue SFC (single-file component).</p><h4><a href="https://mokkapps.de/vue-tips/defining-and-registering-vue-web-components#1-create-the-custom-element">1. Create the custom element</a></h4><p>To create the custom element, we use defineCustomElement:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*qyX2duD1MKhmF8CP" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><p>You may have noticed that our SFC uses the special file ending .ce.vue.</p><p>It inlines the SFC’s &lt;style&gt; tags as strings of CSS and exposes them under the component&#39;s styles option.</p><p>During production build with default tooling setup, the &lt;style&gt; inside the SFCs are extracted and merged into a single CSS file. But for the custom component, the &lt;style&gt; tags should be injected into the custom element&#39;s shadow root.</p><h4><a href="https://mokkapps.de/vue-tips/defining-and-registering-vue-web-components#2-register-the-custom-element-with-the-dom">2. Register the custom element with the DOM</a></h4><p>Next, we can register the custom element using the define method. After registration, all &lt;my-example&gt; tags on the page will be upgraded afterward:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*ze7kFYVETO9Ur1Pi" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><h4><a href="https://mokkapps.de/vue-tips/defining-and-registering-vue-web-components#3-use-the-custom-element-in-your-html">3. Use the custom element in your HTML</a></h4><p>Finally, we can use our custom element in HTML:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*QRfaWuisUwAL2kVF" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><p>Check out the docs for <a href="https://vuejs.org/guide/extras/web-components.html">more details</a> on how this works.</p><h3>Curated Vue Content</h3><h4><a href="https://vueschool.io/articles/vuejs-tutorials/hybrid-rendering-in-nuxt-js-3/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Hybrid Rendering in Nuxt.js 3</a></h4><p><a href="https://vueschool.io/articles/vuejs-tutorials/hybrid-rendering-in-nuxt-js-3/">vueschool.io</a></p><p>👉🏼 Nuxt 3 has a lot of rendering options. There’s SSR, SSG, SPA…</p><p>👉🏻 In this article, Daniel breaks down each option.</p><h4><a href="https://blog.logrocket.com/a-guide-to-automated-testing-in-vue-with-cypress/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 A guide to automated testing in Vue with Cypress</a></h4><p><a href="https://blog.logrocket.com/a-guide-to-automated-testing-in-vue-with-cypress/">blog.logrocket.com</a></p><p>👉🏻 In this article, Paul teaches us how to test individual Vue components with Cypress.</p><p>👉🏻 “If you’re using Vue, Cypress is one of the best tools available for testing your application.”</p><h4><a href="https://viteconf.org/2022/replay/sodatea?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📹 Vue’s Road to Vite</a></h4><p><a href="https://viteconf.org/2022/replay/sodatea">viteconf.org</a></p><p>👉🏻 As Haoqun shared in his talk at ViteConf, it’s not only the speed that makes Vite attractive.</p><p>👉🏻 Slides: <a href="https://docs.google.com/presentation/d/1-J8s31K8eMALYLPaKeyufsglet7OFGejHPDS3zzJvFE/edit">https://docs.google.com...</a></p><h3>TypeScript Tip: Avoid Default Exports</h3><p>Let’s first take a look at an example with default exports using export default:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*WQAByCuTmvykIJXJ" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><p>And now the same example but without the default export:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*JrR2EvUabaoPWUUX" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><p>Why is it better?</p><p>🤜🏻 Better refactoring support</p><p>🤜🏻 Typo protection</p><p>🤜🏻 Better tree shaking</p><p>🤜🏻 Auto import / completion</p><h3>Curated Web Development Content</h3><h4><a href="https://type-level-typescript.com/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Type-level TypeScript</a></h4><p><a href="https://type-level-typescript.com/">type-level-typescript.com</a></p><p>👉🏻 An online course to take your TypeScript skills from intermediate to advanced.</p><p>👉🏻 It will give you a solid understanding of the type system’s fundamentals and guide you through its most advanced features.</p><h4><a href="https://bradfrost.com/blog/post/lets-talk-about-web-components/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Let’s Talk About Web Components</a></h4><p><a href="https://bradfrost.com/blog/post/lets-talk-about-web-components/">bradfrost.com</a></p><p>👉🏻 Brad looks at how web components can help deliver design system component libraries and their compatibility with JS libraries and frameworks.</p><h4><a href="https://blog.gitguardian.com/toyota-accidently-exposed-a-secret-key-publicly-on-github-for-five-years/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Toyota Suffered a Data Breach by Accidentally Exposing A Secret Key Publicly On GitHub</a></h4><p><a href="https://blog.gitguardian.com/toyota-accidently-exposed-a-secret-key-publicly-on-github-for-five-years/">blog.gitguardian.com</a></p><p>👉🏻 Toyota revealed they had accidentally exposed a credential allowing access to customer data in a public GitHub repo for nearly 5 years.</p><h4><a href="https://github.com/fosslife/devtools-x?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">🛠️ DevTools-X</a></h4><p><a href="https://github.com/fosslife/devtools-x">github.com</a></p><p>👉🏻 A cross-platform collection of offline-first developer utilities similar to those native to Mac/Windows.</p><p>👉🏻 Includes utilities for color, images, JSON, Regex, SQL, and even a live React playground.</p><h4><a href="https://surveyjs.io/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">🛠️ SurveyJS</a></h4><p><a href="https://surveyjs.io/">surveyjs.io</a></p><p>👉🏻 A form builder library for creating data-driven, multi-langauge survey forms.</p><p>👉🏻 It has a ‘pro’ level and some related commercial services but is MIT licensed at the base.</p><h4><a href="https://day.js.org/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">🛠️ Day.js</a></h4><p><a href="https://day.js.org/">day.js.org</a></p><p>👉🏻 Fast 2kB alternative to Moment.js with the same modern API.</p><h3>Quote of the Week</h3><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*j8MhyOQZv00WOYYg" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e7f7105518ff" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Weekly Vue News — #65 — Share Composable State Across Components]]></title>
            <link>https://mokkappsdev.medium.com/weekly-vue-news-65-share-composable-state-across-components-4e8b51522d3?source=rss-b6dc9bc6fff4------2</link>
            <guid isPermaLink="false">https://medium.com/p/4e8b51522d3</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Michael Hoffmann]]></dc:creator>
            <pubDate>Mon, 31 Oct 2022 16:09:26 GMT</pubDate>
            <atom:updated>2022-10-31T16:09:26.665Z</atom:updated>
            <content:encoded><![CDATA[<p>Hi 👋</p><p>Last week I finally managed to deploy a static version of my <a href="https://mokkapps.de">portfolio website</a> (developed with Nuxt 3) to Netlify.</p><p>This week I’ll work on some bugfixes for <a href="https://codesnap.dev">CodeSnap.dev</a> and maybe I have time to start writing a new blog post. The next article will be about the Table of Contents component I developed for my portfolio website.</p><p>Have a great week ☀️</p><h3>Vue Tip: Share Composable State Across Components</h3><p>We create a new state on each function call if we define state in a <a href="https://vuejs.org/guide/reusability/composables.html">Vue composable</a>. But sometimes, we want to sync the composable state across components.</p><p>Let’s take a look at a simple example:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*osO74St3rSmYiJ4S" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><p>We define a simple reactive variable cart inside the useCart composable. Every time a component calls useCart, a new state is created.</p><p>The following Stackblitz includes a running demo. Click “Add to cart” on “Component 1” and “Component 2”, and you can see that every component has it’s own cart state:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*LMDpmDKLxQNkWleB" /></figure><p><a href="https://stackblitz.com/edit/vue-demo-share-composable-state-across-components?file=src%2Fcomposables%2FuseCart.ts&amp;utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter"><strong>Vue Share Composable State Across Components — StackBlitz</strong></a><strong> — </strong><a href="https://stackblitz.com/edit/vue-demo-share-composable-state-across-components?file=src/composables/useCart.ts"><strong>stackblitz.com</strong></a></p><p>To keep the same state between every useCart instance, we need to lift he state up outside the function, so it&#39;s created only once:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*N-FOjudZtbROaOt4" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><p>You can test it by yourself in the Stackblitz demo above: Click “Add to shared cart” on “Component 1” and “Component 2”, and you can see that they now share the same state.</p><h3>Curated Vue Content</h3><h4><a href="https://antfu.me/posts/dev-ssr-on-nuxt?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Dev SSR on Nuxt with Vite</a></h4><p><a href="https://antfu.me/posts/dev-ssr-on-nuxt">antfu.me</a></p><p>👉🏻 Anthony Fu guides you through the inner workings of Server-Side rendering in dev mode with Nuxt 3 and how this inspired a larger ecosystem.</p><h4><a href="https://medium.com/ascentic-technology/lets-use-vue3-features-in-your-vue2-project-f81a65ec5267?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Let’s use Vue3 Features in Your Vue2 Project</a></h4><p><a href="https://medium.com/ascentic-technology/lets-use-vue3-features-in-your-vue2-project-f81a65ec5267">medium.com</a></p><p>👉🏻 Chamara explain, how to upgrade your existing Vue2 project to Vue 2.7</p><p>👉🏻 He’ll also explain how to use the mentioned backported features in your project explaining a small application.</p><h4><a href="https://www.youtube.com/watch?t=15135s&amp;utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter&amp;v=Znd11rVHQOE">📹 How Vite Makes Nuxt Possible</a></h4><p><a href="https://www.youtube.com/watch?t=15135s&amp;v=Znd11rVHQOE">www.youtube.com</a></p><p>👉🏻 In this talk from ViteConf 2022, Nuxt core team member Daniel Roe explains how Vite makes Nuxt 3 possible</p><h4><a href="https://nuxt.new/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">🛠️ Start a Nuxt project</a></h4><p><a href="https://nuxt.new/">nuxt.new</a></p><p>👉🏻 Open a Nuxt starter on CodeSandbox or StackBlitz to get up and running in a few seconds.</p><h4><a href="https://vuesax.com/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">🛠️ Vuesax</a></h4><p><a href="https://vuesax.com/">vuesax.com</a></p><p>👉🏻 A framework of UI components created with Vuejs to make projects easily and with a unique and pleasant style.</p><h3>TypeScrip Tip: Lock Types Using Const Assertion</h3><p>When we construct new literal expressions with const assertions, we can signal to the language that</p><p>- no literal types in that expression should be widened (e.g. no going from “hello” to string)</p><p>- object literals get readonly properties</p><p>- array literals become readonly tuples</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*lywlhMTPDk1L3j6g" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><h3>Curated Web Development Content</h3><p>🤣 CSS debugging: The console.log of CSS</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*GbeR_iwrgUCjAwzc" /><figcaption>Image created with CodeSnap.dev</figcaption></figure><h4><a href="https://devblogs.microsoft.com/typescript/ten-years-of-typescript/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Ten Years of TypeScript</a></h4><p><a href="https://devblogs.microsoft.com/typescript/ten-years-of-typescript/">devblogs.microsoft.com</a></p><p>👉🏼 TypeScript’s PM reflects on how its ideas have stood the test of time and looks forward to another ten years.</p><h4><a href="https://www.epicweb.dev/fully-typed-web-apps?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Fully Typed Web Apps (from Kent C. Dodds)</a></h4><p><a href="https://www.epicweb.dev/fully-typed-web-apps">www.epicweb.dev</a></p><p>👉🏻 “Type safety is something that’s not only valuable, but achievable across boundaries end to end.”</p><h4><a href="https://blog.logrocket.com/schema-validation-typescript-zod/?utm_campaign=Weekly%20Vue%20News&amp;utm_medium=email&amp;utm_source=Revue%20newsletter">📕 Schema validation in TypeScript with Zod</a></h4><p><a href="https://blog.logrocket.com/schema-validation-typescript-zod/">blog.logrocket.com</a></p><p>👉🏻 Zod is a tool that fills this TypeScript blindspot and helps with type safety during runtime.</p><p>👉🏻 It can help you build a pretty flexible Schema design and run it against a form or user input.</p><h3>Quote of the Week</h3><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/0*HkktAxjKAn1Nkm_4" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4e8b51522d3" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>