<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[natterstefan]]></title><description><![CDATA[Hey 👋🏻,

I am a Software Engineer from Austria 🇦🇹. I am interested in, write about, and develop (open source) software solutions for and with JavaScript, Ty]]></description><link>https://blog.natterstefan.me</link><generator>RSS for Node</generator><lastBuildDate>Wed, 22 Apr 2026 04:20:58 GMT</lastBuildDate><atom:link href="https://blog.natterstefan.me/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Start Over Again and Unmute All Twitter Users.]]></title><description><![CDATA["Twitter is the home of the trolls." You've probably heard this statement many times from your Twitter friends. That's why mute lists might grow all the time. The mute feature ensures that you do not see a tweet from a Twitter user, but you can still...]]></description><link>https://blog.natterstefan.me/start-over-again-and-unmute-all-twitter-users</link><guid isPermaLink="true">https://blog.natterstefan.me/start-over-again-and-unmute-all-twitter-users</guid><category><![CDATA[Twitter]]></category><category><![CDATA[cli]]></category><category><![CDATA[APIs]]></category><dc:creator><![CDATA[Stefan Natter]]></dc:creator><pubDate>Tue, 16 Mar 2021 06:20:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1615840242770/iaQ4LAEod.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>"Twitter is the home of the trolls."</em> You've probably heard this statement many times from your Twitter friends. That's why mute lists might grow all the time. The mute feature ensures that you do not see a tweet from a Twitter user, but you can still visit the user's profile. It is a friendlier way than blocking users. Be aware that muted users can still interact with your profile, you just do not see it. That confused me from time to time. Because I saw that a user interacted with my tweet, but I did not saw the response when I opened the tweet. You can only see it if you open the tweet in another browser.</p>
<h2 id="tweepy">Tweepy</h2>
<p>And so it happened that I wanted to reset my mute list. But that turned out to be a time-consuming task. On the iPhone as well as on the Mac it is tedious to click through all users and unmute them. For this reason, I looked around for a more efficient solution. Thereby I stumbled over <a target="_blank" href="https://nttr.st/3vCsCDJ">Tweepy</a>.</p>
<blockquote>
<p>Tweepy is an easy-to-use Python library to access the Twitter API.</p>
</blockquote>
<p>I want to tell you upfront that you need a Twitter Developer account and application to use Tweepy. To do this, you need to create an account on <a target="_blank" href="https://nttr.st/3qOkGvf">developers.twitter.com</a> and create an application. Since Twitter has changed the process, this may take some time. You should keep that in mind.</p>
<p>However, it is the safest and best way to reset the mute list. Other alternatives with JavaScript scripts or browser extensions don't seem to be a good idea.</p>
<h2 id="install-tweepy">Install Tweepy</h2>
<p>Before you can use Tweepy you have to <a target="_blank" href="https://docs.tweepy.org/en/latest/install.html">install it</a>.</p>
<pre><code class="lang-bash">pip install tweepy
</code></pre>
<h2 id="use-tweepy-to-unmute-people">Use Tweepy to Unmute People</h2>
<p>You can either write your own Tweepy script or use the one I found when looking up "how to unmute people on Twitter" on Google. I used <a target="_blank" href="https://gist.github.com/miguelgarcia/bd513d5deb0fd59b1404a86c146c8410">this gist by Miguel Garcia</a> to reset my list.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> tweepy

consumer_key = <span class="hljs-string">''</span>
consumer_secret = <span class="hljs-string">''</span>
access_token = <span class="hljs-string">''</span>
access_token_secret = <span class="hljs-string">''</span>

auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)

api = tweepy.API(auth, wait_on_rate_limit=<span class="hljs-literal">True</span>)
api.verify_credentials()

<span class="hljs-keyword">for</span> u <span class="hljs-keyword">in</span> tweepy.Cursor(api.mutes).items():
    print(<span class="hljs-string">f"Unmutting <span class="hljs-subst">{u.screen_name}</span>"</span>)
    api.destroy_mute(u.id)
</code></pre>
<p>Add the <code>consumer_key</code> and the other secrets from your Twitter application and start the script with <code>python main.py</code>.</p>
<p>You should see "Unmutting username" in the logs until Tweepy detects the rate limit. It will then stop and continue once it's safe again. Depending on the number of people on your mute list it can take some time to reset it.</p>
<p>That's it. Now you have reset your mute list and start over again.</p>
<h2 id="further-reading">Further Reading</h2>
<ul>
<li><a target="_blank" href="https://docs.tweepy.org/en/latest/index.html">Tweepy Documentation — tweepy 3.10.0 documentation</a></li>
<li><a target="_blank" href="https://realpython.com/twitter-bot-python-tweepy/">How to Make a Twitter Bot in Python With Tweepy – Real Python</a></li>
</ul>
<hr />
<h2 id="share">Share 💛</h2>
<p>Do you like this article? Do you want to support me? <a target="_blank" href="https://ctt.ac/140Ap">Tell your friends on Twitter</a> about it. Thank you!</p>
<h2 id="questions-and-feedback">Questions and Feedback</h2>
<p>You got any questions or want to add your thoughts? Let me know in the comments below, please.</p>
<h2 id="lets-connect">Let's connect</h2>
<div class="hn-embed-widget" id="newsletter-form"></div><hr />
<p><em>Image: https://unsplash.com/photos/BcjdbyKWquw</em></p>
]]></content:encoded></item><item><title><![CDATA[How to Use Multiple Node Version With asdf.]]></title><description><![CDATA[If you work a lot with Node projects, it often happens that you need to change the Node version. Older projects may still be running on Node 10 or 12, while newer ones already use Node 14. To quickly switch between versions, many people use nvm (node...]]></description><link>https://blog.natterstefan.me/how-to-use-multiple-node-version-with-asdf</link><guid isPermaLink="true">https://blog.natterstefan.me/how-to-use-multiple-node-version-with-asdf</guid><category><![CDATA[Node.js]]></category><category><![CDATA[npm]]></category><category><![CDATA[Productivity]]></category><category><![CDATA[cli]]></category><dc:creator><![CDATA[Stefan Natter]]></dc:creator><pubDate>Tue, 09 Mar 2021 08:48:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1615280210436/XHai-ZmzB.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you work a lot with Node projects, it often happens that you need to change the Node version. Older projects may still be running on Node 10 or 12, while newer ones already use Node 14. To quickly switch between versions, many people use <a target="_blank" href="https://github.com/nvm-sh/nvm">nvm</a> (node version manager). nvm is a well-tried and well-known version manager for Node (like <a target="_blank" href="https://github.com/pyenv/pyenv">pyenv</a>  or <a target="_blank" href="https://pypi.org/project/virtualenv/">virtualenv</a> for Python). I myself used nvm for years until I was finally introduced to asdf. asdf has become my favorite and has replaced all other version managers because asdf supports multiple languages at once (Ruby, Node.js, Python, Elixir, Erlang &amp; more)!</p>
<p>You may think that a handstand is necessary to use asdf as the primary version manager, but I can assure you that is not necessary. With a few commands (FTR: I only talk about macOS in this article) you have asdf installed and ready to go.</p>
<h2 id="install">Install</h2>
<p>On their website, <a target="_blank" href="https://asdf-vm.com/#/core-manage-asdf">select your operating system and installation method</a>. For this tutorial, I have chosen macOS and Homebrew. Execute the following commands in this order to install and set up <code>asdf</code>:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># install required dependencies</span>
brew install coreutils curl git

<span class="hljs-comment"># install asdf</span>
brew install asdf

<span class="hljs-comment"># add it to your shell</span>
<span class="hljs-built_in">echo</span> -e <span class="hljs-string">"\n. <span class="hljs-subst">$(brew --prefix asdf)</span>/asdf.sh"</span> &gt;&gt; ~/.bash_profile

<span class="hljs-comment"># set up bash completions</span>
<span class="hljs-built_in">echo</span> -e <span class="hljs-string">"\n. <span class="hljs-subst">$(brew --prefix asdf)</span>/etc/bash_completion.d/asdf.bash"</span> &gt;&gt; ~/.bash_profile
</code></pre>
<p>Once you have installed the commands you should see which version you have installed when executing <code>asdf --version</code>. In my case, I get <code>v0.8.0</code>.</p>
<h2 id="how-to-install-plugins-and-versions">How to Install Plugins and Versions</h2>
<p>One thing you need to know about asdf is that each supported language requires a plugin which in turn manages the versions of the language. Therefore, you must first install the necessary plugin and then the versions. Let's see how this looks like for Node.js.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># install the package</span>
asdf plugin add &lt;name&gt;
<span class="hljs-comment"># asdf plugin add nodejs</span>

<span class="hljs-comment"># get a list of installed plugins</span>
asdf plugin list

<span class="hljs-comment"># update plugin(s)</span>
asdf plugin update &lt;name&gt;
asdf plugin update --all

<span class="hljs-comment"># remove plugin</span>
asdf plugin remove &lt;name&gt;
<span class="hljs-comment"># asdf plugin remove nodejs</span>
</code></pre>
<p>Now that we have Node.js installed, let's see how we can install one or more versions. Again, this can be done with a few simple commands.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># install version for package</span>
asdf install &lt;name&gt; &lt;version&gt;
<span class="hljs-comment"># asdf install nodejs 14.15.4</span>

<span class="hljs-comment"># list installed versions</span>
asdf list &lt;name&gt;

<span class="hljs-comment"># list all versions</span>
asdf list all &lt;name&gt;
</code></pre>
<h2 id="how-to-set-the-current-plugin-version">How To Set the Current Plugin Version</h2>
<p>Once you installed the plugin <code>nodejs</code> with the required version you can choose to either set and use this version globally, in your current shell, or in the current project folder.</p>
<pre><code class="lang-bash">asdf global &lt;name&gt; &lt;version&gt; [&lt;version&gt;...]
asdf shell &lt;name&gt; &lt;version&gt; [&lt;version&gt;...]
asdf <span class="hljs-built_in">local</span> &lt;name&gt; &lt;version&gt; [&lt;version&gt;...]
<span class="hljs-comment"># asdf global nodejs 14.15.4</span>
</code></pre>
<p><code>asdf global</code> will write the selected version to <code>$HOME/.tool-versions</code> (<a target="_blank" href="https://asdf-vm.com/#/core-configuration?id=tool-versions">docs</a>). <code>asdf shell</code> only to the current shell, which can be different compared to other shells. <code>asdf local</code> writes the version to <code>$PWD/.tool-versions</code>. This is the file I check in in my repositories (<a target="_blank" href="https://github.com/natterstefan/nodejs-playground/blob/main/.tool-versions">example</a>) to share the used versions of a project with other contributors.</p>
<p>When you set the version globally or locally you can verify that asdf has selected the proper version by running <code>node --version</code>. It should automatically switch it based on your settings now.</p>
<p>You do not need to add a script to your <code>.bash_profile</code> to do this automatically as you have with <code>nvm</code>(<a target="_blank" href="https://github.com/nvm-sh/nvm/tree/d9b11ba20843c8bc10772157571a67b9076b7ba5#deeper-shell-integration">this is how you do this with nvm</a>).</p>
<h2 id="legacy-support">Legacy Support</h2>
<p>You may ask yourself how you can use asdf when other colleagues still use <code>nvm</code>, do you? It is possible thanks to the legacy support asdf provides. Add a <code>.asdfrc</code> file to your home directory and specify the following settings. This will enable legacy support for files like <code>.node-version</code> or <code>.nvmrc</code>.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># .asdfrc</span>
legacy_version_file = yes
</code></pre>
<p>But I am sure that you will want to ask your colleagues to switch to asdf too, once you got used to it. That's what I did at least.</p>
<h2 id="summary">Summary</h2>
<p>Because asdf supports multiple languages almost out of the box, you can remove almost all the other version managers or gradually move to asdf. I highly recommend asdf, since it has made version management a lot easier for me. Check out their <a target="_blank" href="https://asdf-vm.com/">well-written docs for more details</a>.</p>
<p>Feel free to reach out to me on <a target="_blank" href="https://twitter.com/intent/follow?screen_name=natterstefan">Twitter</a> or in the comments below if you have more questions and input. </p>
<hr />
<h2 id="share">Share 💛</h2>
<p>Do you like this article? Do you want to support me? <a target="_blank" href="https://ctt.ac/gD2cW">Tell your friends on Twitter</a> about it. Thank you!</p>
<h2 id="questions-and-feedback">Questions and Feedback</h2>
<p>You got any questions or want to add your thoughts? Let me know in the comments below, please.</p>
<h2 id="lets-connect">Let's connect</h2>
<div class="hn-embed-widget" id="newsletter-form"></div>]]></content:encoded></item><item><title><![CDATA[Git: Automatically Lint Your Code or Run Tests on `git push` with Git Hooks]]></title><description><![CDATA[Git Hooks are scripts that run automatically every time you run a specific command (e.g. git push) in a Git repository. They allow you to customize parts of your development flow for the better (IMHO). You can lint staged files, run tests before you ...]]></description><link>https://blog.natterstefan.me/git-automatically-lint-your-code-or-run-tests-on-git-push-with-git-hooks</link><guid isPermaLink="true">https://blog.natterstefan.me/git-automatically-lint-your-code-or-run-tests-on-git-push-with-git-hooks</guid><category><![CDATA[GitHub]]></category><category><![CDATA[Git]]></category><category><![CDATA[npm]]></category><category><![CDATA[Node.js]]></category><dc:creator><![CDATA[Stefan Natter]]></dc:creator><pubDate>Sun, 28 Feb 2021 19:07:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1614539126001/JqGygiRyS.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Git Hooks are scripts that run automatically every time you run a specific command (e.g. <code>git push</code>) in a Git repository. They allow you to customize parts of your development flow for the better (IMHO). You can lint staged files, run tests before you push the code, or lint the commit-message (which is useful when using automated version management tools like <a target="_blank" href="https://github.com/semantic-release/semantic-release">semantic-release</a>).</p>
<hr />
<p>Right upfront, I'm a fan of git hooks. But, they are not without controversy. At least in the teams, I was in. Not everyone recognized the benefits of Git Hooks. I think that Git Hooks - especially together with ESLint, Prettier, and others - enforce a code standard, -quality, warn about common errors, bad practices, mistakes and point out errors earlier.</p>
<p>Sure, these checks can also be performed with the help of <a target="_blank" href="https://www.travis-ci.com/">Travis CI</a> and others. This is true, but it takes a while for these checks to run, and in that time you have to wait for the results - <em>before</em> you can act. So I prefer to run them locally myself and see what I'm about to push to origin. This is especially the case if you are using Travis' smaller plans. You'd need to wait until the other tasks on Travis are completed before your commit is validated. This can take time, especially in bigger teams.</p>
<p>I often heard that engineers do not want to wait until the hooks are completed but want to push immediately. I can only counter that, if it is really necessary there is still the possibility to bypass the Git hooks with <code>--no-verify</code>. But to reject them from the beginning I think is the wrong way IMHO.</p>
<h2 id="how-to-set-up-husky">How to set up husky</h2>
<p>Let's look at one known player in the node-world for git hooks: <a target="_blank" href="https://www.npmjs.com/package/husky">husky</a>.</p>
<p>It is easy to install and prepare Git hooks with this command (<a target="_blank" href="https://typicode.github.io/husky/#/">docs</a>).</p>
<pre><code class="lang-bash"><span class="hljs-comment"># install husky and create a sample pre-commit hook</span>
npm install husky --save-dev &amp;&amp; npm <span class="hljs-built_in">exec</span> husky init
</code></pre>
<p>The default git hook will run <code>npm test</code> when you commit. You can see the git hook in the <code>./husky</code> folder <code>husky</code> created during the setup. We want to have a hook that automatically lints our code when we push commits. So let's add a git hook manually.</p>
<p><em>Note: I assume that you have installed and set up ESLint already.</em></p>
<p>With the following command, we add a <code>pre-push</code> hook.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># runs ESLint on git push (<span class="hljs-doctag">TODO:</span> check)</span>
npx husky add .husky/pre-push <span class="hljs-string">'npm run eslint . "$1"'</span>
</code></pre>
<p>If you commit and push a change now, you'll see that husky executes <code>npm run eslint .</code> first. When the command exits successfully it will allow the push, if not the push will be aborted.</p>
<p>Take a closer look a the <code>.husky/pre-push</code> file. It is easy to see how you can extend the generated hooks. Simply edit it and add new commands. This is how it looks in one of my projects now:</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/sh</span>
. <span class="hljs-string">"<span class="hljs-subst">$(dirname <span class="hljs-string">"<span class="hljs-variable">$0</span>"</span>)</span>/_/husky.sh"</span>

yarn lint
yarn <span class="hljs-built_in">test</span>
</code></pre>
<p>This will first lint my code and then run the tests. Because this is a simple bash file you can do whatever you want to do with bash commands.</p>
<p>It is up to you what you want to do with git-hooks. You can lint commit messages, run tests, and more. Talk with your team and think about different use-cases. I am sure you can come up with some.</p>
<h2 id="summary">Summary</h2>
<p>Once you add and use git hooks you probably want to take care of other use-cases as well. For instance, how can you <a target="_blank" href="https://typicode.github.io/husky/#/?id=bypass-hooks">bypass the hooks</a> and how to <a target="_blank" href="https://typicode.github.io/husky/#/?id=disable-hooks-in-ci">disable them in CI</a>. The <a target="_blank" href="https://typicode.github.io/husky/#/">husky docs are great</a>, they did a decent job in explaining how to use husky in different use-cases. Take a look at them if you are lost.</p>
<p>All in all, I am a fan of git hooks, as I said at the beginning of this article. Git Hooks may slow down pushing or committing, but in the long run, you benefit from those few seconds you have to wait for the feedback of the hook.</p>
<hr />
<h2 id="share">Share 💛</h2>
<p>Do you like this article? Do you want to support me? <a target="_blank" href="https://ctt.ac/0Eb4t">Tell your friends on Twitter</a> about it. Thank you!</p>
<h2 id="questions-and-feedback">Questions and Feedback</h2>
<p>You got any questions or want to add your thoughts? Let me know in the comments below, please.</p>
<h2 id="lets-connect">Let's connect</h2>
<div class="hn-embed-widget" id="newsletter-form"></div>]]></content:encoded></item><item><title><![CDATA[How to Dockerize a NextJS application]]></title><description><![CDATA[Next.js lets you build production-grade applications that scale with ease. You can build static and dynamic websites with world-class development experience. The team behind Guillermo Rauch has built an environment that is preferred by thousands of s...]]></description><link>https://blog.natterstefan.me/how-to-dockerize-a-nextjs-application</link><guid isPermaLink="true">https://blog.natterstefan.me/how-to-dockerize-a-nextjs-application</guid><category><![CDATA[Docker]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[deployment]]></category><dc:creator><![CDATA[Stefan Natter]]></dc:creator><pubDate>Sat, 27 Feb 2021 16:35:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1614443997175/xq06KsEKQ.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Next.js lets you build production-grade applications that scale with ease. You can build static and dynamic websites with world-class development experience. The team behind Guillermo Rauch has built an environment that is preferred by thousands of software engineering teams every day.</p>
<p>So did we for our company projects. At my company marqant digital, we have decided to not build a custom-built application setup (with SSR, etc.) again, but to use an already existing solution. We were faced with a decision between Gatsby and Next.js. Although I think Gatsby is also great software, the requirements of the project favored Vercel's product.</p>
<p>And as with all other (micro-)services we build and use around our products, our React and Node applications need to run in a Docker environment. To expand my digital garden, and at the same time provide you with added value, I share with you our latest Dockerfile we use in our Next.js projects.</p>
<p>I assume you have <a target="_blank" href="https://www.docker.com/products/docker-desktop">Docker Desktop</a> installed, have worked with Docker, and have a knowledge of the basics of Next.js.</p>
<h2 id="multi-stage-dockerfile-for-nextjs-applications">Multi-Stage Dockerfile for Next.js Applications</h2>
<p>Let's take a look at our current Dockerfile. You might know some of the things I do here already, but let's take a look at each one of them in detail. If you build a static site with Next.js you might not need all the stages and layers we use in our Dockerfile. But our app requires us to use Next.js this way. So keep that in mind, when using the solution below, please. Here's the complete Dockerfile.</p>
<pre><code class="lang-yaml"><span class="hljs-string">ARG</span> <span class="hljs-string">node_version=14.15.4</span>
<span class="hljs-string">ARG</span> <span class="hljs-string">node_image=node:${node_version}-alpine</span>

<span class="hljs-comment"># STAGE 1</span>
<span class="hljs-string">FROM</span> <span class="hljs-string">$node_image</span> <span class="hljs-string">as</span> <span class="hljs-string">builder</span>

<span class="hljs-string">ENV</span> <span class="hljs-string">NEXT_TELEMETRY_DISABLED=1</span>

<span class="hljs-string">WORKDIR</span> <span class="hljs-string">/app/</span>

<span class="hljs-string">COPY</span> <span class="hljs-string">package.json</span> <span class="hljs-string">yarn.lock</span> <span class="hljs-string">./</span>
<span class="hljs-string">RUN</span> <span class="hljs-string">yarn</span> <span class="hljs-string">install</span> <span class="hljs-string">--frozen-lockfile</span> <span class="hljs-string">--no-progress</span>

<span class="hljs-string">COPY</span> <span class="hljs-string">next.config.js</span> <span class="hljs-string">./</span>
<span class="hljs-string">COPY</span> <span class="hljs-string">components</span> <span class="hljs-string">./components/</span>
<span class="hljs-string">COPY</span> <span class="hljs-string">pages</span> <span class="hljs-string">./pages/</span>
<span class="hljs-string">COPY</span> <span class="hljs-string">public</span> <span class="hljs-string">./public/</span>
<span class="hljs-string">COPY</span> <span class="hljs-string">styles</span> <span class="hljs-string">./styles/</span>

<span class="hljs-string">RUN</span> <span class="hljs-string">yarn</span> <span class="hljs-string">build</span>

<span class="hljs-comment"># STAGE 2</span>
<span class="hljs-string">FROM</span> <span class="hljs-string">$node_image</span> <span class="hljs-string">as</span> <span class="hljs-string">production</span>

<span class="hljs-string">WORKDIR</span> <span class="hljs-string">/app/</span>

<span class="hljs-string">COPY</span> <span class="hljs-string">--from=builder</span> <span class="hljs-string">/app/package.json</span> <span class="hljs-string">/app/yarn.lock</span> <span class="hljs-string">./</span>
<span class="hljs-string">RUN</span> <span class="hljs-string">yarn</span> <span class="hljs-string">install</span> <span class="hljs-string">--frozen-lockfile</span> <span class="hljs-string">--production=true</span> <span class="hljs-string">--no-progress</span>

<span class="hljs-comment"># STAGE 3</span>
<span class="hljs-string">FROM</span> <span class="hljs-string">$node_image</span>

<span class="hljs-string">ENV</span> <span class="hljs-string">NEXT_TELEMETRY_DISABLED=1</span>
<span class="hljs-string">ENV</span> <span class="hljs-string">NODE_ENV=production</span>

<span class="hljs-string">WORKDIR</span> <span class="hljs-string">/app/</span>

<span class="hljs-string">COPY</span> <span class="hljs-string">--from=production</span> <span class="hljs-string">/app/node_modules</span> <span class="hljs-string">./node_modules</span>
<span class="hljs-string">COPY</span> <span class="hljs-string">--from=builder</span> <span class="hljs-string">/app/.next</span> <span class="hljs-string">./.next</span>
<span class="hljs-string">COPY</span> <span class="hljs-string">--from=builder</span> <span class="hljs-string">/app/next.config.js</span> <span class="hljs-string">./</span>
<span class="hljs-string">COPY</span> <span class="hljs-string">--from=builder</span> <span class="hljs-string">/app/public</span> <span class="hljs-string">./public</span>
<span class="hljs-string">COPY</span> <span class="hljs-string">--from=builder</span> <span class="hljs-string">/app/package.json</span> <span class="hljs-string">./</span>

<span class="hljs-string">EXPOSE</span> <span class="hljs-number">3000</span>
<span class="hljs-string">CMD</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">start</span>
</code></pre>
<p>What you see here is a <a target="_blank" href="https://docs.docker.com/develop/develop-images/multistage-build/">multi-stage Dockerfile</a>. By using multiple stages you can significantly reduce the size of a Docker image. This is due to the fact that you only copy what you need from the previous stage to the next one.</p>
<p>Let's take a look at each stage individually. Let's start with Stage 1.</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># Because we use more than one stage, we use ARG</span>
<span class="hljs-comment"># to determine some global variables in our</span>
<span class="hljs-comment"># Dockerfile. In this case, our node_version and the</span>
<span class="hljs-comment"># selected docker base image.</span>
<span class="hljs-string">ARG</span> <span class="hljs-string">node_version=14.15.4</span>
<span class="hljs-string">ARG</span> <span class="hljs-string">node_image=node:${node_version}-alpine</span>

<span class="hljs-comment"># STAGE 1 is called "builder"</span>
<span class="hljs-comment"># We can reference this name later</span>
<span class="hljs-string">FROM</span> <span class="hljs-string">$node_image</span> <span class="hljs-string">as</span> <span class="hljs-string">builder</span>

<span class="hljs-comment"># disable Next.js' analytics (https://nextjs.org/telemetry)</span>
<span class="hljs-string">ENV</span> <span class="hljs-string">NEXT_TELEMETRY_DISABLED=1</span>

<span class="hljs-comment"># everything we do will happen in this folder in the image</span>
<span class="hljs-string">WORKDIR</span> <span class="hljs-string">/app/</span>

<span class="hljs-comment"># configs and dependency handling</span>
<span class="hljs-string">COPY</span> <span class="hljs-string">package.json</span> <span class="hljs-string">yarn.lock</span> <span class="hljs-string">./</span>

<span class="hljs-comment"># install all dependencies</span>
<span class="hljs-string">RUN</span> <span class="hljs-string">yarn</span> <span class="hljs-string">install</span> <span class="hljs-string">--frozen-lockfile</span> <span class="hljs-string">--no-progress</span>

<span class="hljs-comment"># copy source code of our app</span>
<span class="hljs-string">COPY</span> <span class="hljs-string">next.config.js</span> <span class="hljs-string">./</span>
<span class="hljs-string">COPY</span> <span class="hljs-string">components</span> <span class="hljs-string">./components/</span>
<span class="hljs-string">COPY</span> <span class="hljs-string">pages</span> <span class="hljs-string">./pages/</span>
<span class="hljs-string">COPY</span> <span class="hljs-string">public</span> <span class="hljs-string">./public/</span>
<span class="hljs-string">COPY</span> <span class="hljs-string">styles</span> <span class="hljs-string">./styles/</span>

<span class="hljs-comment"># build the app</span>
<span class="hljs-string">RUN</span> <span class="hljs-string">yarn</span> <span class="hljs-string">build</span>
</code></pre>
<p>Now we install only the production dependencies in Stage 2 as a preparation for the last and final Stage 3.</p>
<pre><code class="lang-yml"><span class="hljs-comment"># STAGE 2</span>
<span class="hljs-string">FROM</span> <span class="hljs-string">$node_image</span> <span class="hljs-string">as</span> <span class="hljs-string">production</span>

<span class="hljs-string">WORKDIR</span> <span class="hljs-string">/app/</span>

<span class="hljs-string">COPY</span> <span class="hljs-string">--from=builder</span> <span class="hljs-string">/app/package.json</span> <span class="hljs-string">/app/yarn.lock</span> <span class="hljs-string">./</span>
<span class="hljs-string">RUN</span> <span class="hljs-string">yarn</span> <span class="hljs-string">install</span> <span class="hljs-string">--frozen-lockfile</span> <span class="hljs-string">--production=true</span> <span class="hljs-string">--no-progress</span>
</code></pre>
<p>In Stage 3 we copy the results from Stage 1 (the finished application) and Stage 2 (the production node dependencies) together and start the app. This is what it looks like.</p>
<pre><code class="lang-yml"><span class="hljs-comment"># STAGE 3</span>
<span class="hljs-string">FROM</span> <span class="hljs-string">$node_image</span>

<span class="hljs-string">ENV</span> <span class="hljs-string">NEXT_TELEMETRY_DISABLED=1</span>
<span class="hljs-string">ENV</span> <span class="hljs-string">NODE_ENV=production</span>

<span class="hljs-string">WORKDIR</span> <span class="hljs-string">/app/</span>

<span class="hljs-comment"># copy the production node_modules from STAGE 2</span>
<span class="hljs-string">COPY</span> <span class="hljs-string">--from=production</span> <span class="hljs-string">/app/node_modules</span> <span class="hljs-string">./node_modules</span>

<span class="hljs-comment"># copy the result from the builder (STAGE 1)</span>
<span class="hljs-comment"># where we built the app into STAGE 3</span>
<span class="hljs-string">COPY</span> <span class="hljs-string">--from=builder</span> <span class="hljs-string">/app/.next</span> <span class="hljs-string">./.next</span>
<span class="hljs-string">COPY</span> <span class="hljs-string">--from=builder</span> <span class="hljs-string">/app/next.config.js</span> <span class="hljs-string">./</span>
<span class="hljs-string">COPY</span> <span class="hljs-string">--from=builder</span> <span class="hljs-string">/app/public</span> <span class="hljs-string">./public</span>
<span class="hljs-string">COPY</span> <span class="hljs-string">--from=builder</span> <span class="hljs-string">/app/package.json</span> <span class="hljs-string">./</span>

<span class="hljs-string">EXPOSE</span> <span class="hljs-number">3000</span>
<span class="hljs-string">CMD</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">start</span>
</code></pre>
<p>That is our Dockerfile. If you now run this image you have a production-ready Next.js application.</p>
<p>The easiest way to start the image is with the help of docker-compose and this <code>docker-compose.yml</code> file. Create the file and simply run <code>docker-compose up</code>. After the image is built, you should see some logs indicating that the app has started. You can now open <code>localhost:3000</code> again in your browser and you are done.</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># docker-compose.yml</span>
<span class="hljs-attr">version:</span> <span class="hljs-string">"3.8"</span>

<span class="hljs-attr">services:</span>
  <span class="hljs-attr">app:</span>
    <span class="hljs-attr">build:</span>
      <span class="hljs-attr">context:</span> <span class="hljs-string">.</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"3000:3000"</span>
</code></pre>
<p>PS: <a target="_blank" href="https://github.com/vercel/next.js/blob/canary/docs/deployment.md#docker-image">Take a look at the official Next.js docs</a> for further details about how to dockerize Next.js.</p>
<hr />
<h2 id="share">Share 💛</h2>
<p>Do you like this article? Do you want to support me? <a target="_blank" href="https://ctt.ac/dE1x_">Tell your friends on Twitter</a> about it. Thank you!</p>
<h2 id="questions-and-feedback">Questions and Feedback</h2>
<p>You got any questions or want to add your thoughts? Let me know in the comments below, please.</p>
<h2 id="lets-connect">Let's connect</h2>
<div class="hn-embed-widget" id="newsletter-form"></div>]]></content:encoded></item><item><title><![CDATA[My Favorite Visual Studio Code Extensions - Part I]]></title><description><![CDATA[From time to time, many dev bloggers seem to publish a "Best of VS Code Extensions". I am now one of them and don't want to make an exception here. In today's blog post I'll show you a few of my favorite VS Code Extensions. Since I have a lot of exte...]]></description><link>https://blog.natterstefan.me/my-favorite-visual-studio-code-extensions-part-i</link><guid isPermaLink="true">https://blog.natterstefan.me/my-favorite-visual-studio-code-extensions-part-i</guid><category><![CDATA[Visual Studio Code]]></category><category><![CDATA[Productivity]]></category><category><![CDATA[code]]></category><category><![CDATA[eslint]]></category><category><![CDATA[General Programming]]></category><dc:creator><![CDATA[Stefan Natter]]></dc:creator><pubDate>Fri, 26 Feb 2021 20:15:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1614370268608/N51MGHCpc.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>From time to time, many dev bloggers seem to publish a "Best of VS Code Extensions". I am now one of them and don't want to make an exception here. In today's blog post I'll show you a few of my favorite VS Code Extensions. Since I have a lot of extensions installed, I decided to publish it in several parts. Today we will look at part one.</p>
<h2 id="my-favorite-visual-studio-code-extensions">My Favorite Visual Studio Code Extensions</h2>
<h3 id="bookmarks">Bookmarks</h3>
<p>Before I found Bookmarks, I had to keep important parts of the code in mind. This went well at first, but as the project grew in size, it became more and more difficult. Now I create bookmarks and jump back and forth so quickly.</p>
<p>-&gt; https://marketplace.visualstudio.com/items?itemName=alefragnani.Bookmarks</p>
<h3 id="change-case">change-case</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1614357753117/spqHm_8dc.png" alt="change-case" /></p>
<p>Do you often need to quickly change the case of your selection or current word? Then change-case is for you.</p>
<p>-&gt; https://marketplace.visualstudio.com/items?itemName=wmaurer.change-case</p>
<h3 id="docker">Docker</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1614357939574/YWXIGBCud.png" alt="Docker Extensions" /></p>
<p>Again and again, forget various Docker CLI commands. You might feel the same way. With this Docker extension for VS Code, you can perform various tasks in popular IDE. Build a Docker image, launch an image, view running containers, networks, and more. If you are struggling with CLI commands then this extension is very helpful.</p>
<p>-&gt; https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker</p>
<h3 id="eslint">ESLint</h3>
<p>I am a very big fan of Code Linting. With the help of ESLint, you not only ensure certain code quality but also make sure that a code style is maintained. Furthermore, it helps you to avoid common mistakes. This is a must-have extension for me.</p>
<p>-&gt; https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint</p>
<h3 id="file-utils">File Utils</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1614358253519/hViK5aqgk.png" alt="File Utils Extension" /></p>
<p>It is important to have a standard for naming files and folder structure in a project. This makes it easier for newcomers to find their way around. If you accidentally renamed the new file, you can quickly fix the error with this extension.</p>
<p>-&gt; https://marketplace.visualstudio.com/items?itemName=sleistner.vscode-fileutils</p>
<h3 id="gitlense">GitLense</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1614365002741/HIjLGJ804.png" alt="GitLense extensions" /></p>
<p>GitLense is THE Git extension you want to have in my opinion. With GitLense you can quickly view the diffs of your current changes, see when the line was last edited (Line Blame), and more. Check out the marketplace page to see all the features.</p>
<p>-&gt; https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens</p>
<h3 id="headwind">Headwind</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1614365052275/cXObPP38E.png" alt="Headwind Extensions" /></p>
<blockquote>
<p>opinionated Tailwind CSS class sorter for Visual Studio Code</p>
</blockquote>
<p>That is what Headwind is all about. <a class="user-mention" href="https://hashnode.com/@dailydevtips">Chris Bongers</a> shared the extension with me and I love it. Thanks again. I was already looking for an extension like this in the past. Finally, my <code>className</code> values have all the same order.</p>
<p>-&gt; https://marketplace.visualstudio.com/items?itemName=heybourn.headwind</p>
<h3 id="indent-rainbow">indent-rainbow</h3>
<p>The name may make you smile at first sight, but I can tell you that the extension is very helpful. You see at first glance and without having to think much about how the indentations are related.</p>
<p>-&gt; https://marketplace.visualstudio.com/items?itemName=oderwat.indent-rainbow</p>
<h3 id="indenticator">Indenticator</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1614369067762/Ey05BIv9z.png" alt="Indenticator Extension" /></p>
<p>Similar to indent-rainbow this extension highlights the current indent depth too. Especially in larger files, this is very handy.</p>
<p>-&gt; https://marketplace.visualstudio.com/items?itemName=SirTori.indenticator</p>
<h3 id="intellisense-for-css-class-names-in-html">IntelliSense for CSS class names in HTML</h3>
<p>IntelliSense makes your life easier. It provides code-completion, content assistance, and code hints for your codebase. Visual Studio Code comes with IntelliSense built-in, but you can install additional ones, like this one. It provides CSS class name completion in HTML.</p>
<p>-&gt; https://marketplace.visualstudio.com/items?itemName=Zignd.html-css-class-completion</p>
<hr />
<h2 id="share">Share 💛</h2>
<p>Do you like this article? Do you want to support me? <a target="_blank" href="https://ctt.ac/C5FdD">Tell your friends on Twitter</a> about it. Thank you!</p>
<h2 id="questions-and-feedback">Questions and Feedback</h2>
<p>You got any questions or want to add your thoughts? Let me know in the comments below, please.</p>
<h2 id="lets-connect">Let's connect</h2>
<div class="hn-embed-widget" id="newsletter-form"></div>]]></content:encoded></item><item><title><![CDATA[Twitter Growth Hack: Get the best performance by publishing when your audience is most engaged.]]></title><description><![CDATA[As you might know from Catalin's "Improve Your Online Presence" and Danny Thompson's "HOW TO GET FOLLOWERS ON TWITTER! How I went from 0 to 30k Followers in 90 Days!" successful Twitter courses already, engagement on Twitter is one of the most import...]]></description><link>https://blog.natterstefan.me/twitter-growth-hack-get-the-best-performance-by-publishing-when-your-audience-is-most-engaged</link><guid isPermaLink="true">https://blog.natterstefan.me/twitter-growth-hack-get-the-best-performance-by-publishing-when-your-audience-is-most-engaged</guid><category><![CDATA[Twitter]]></category><category><![CDATA[#growth]]></category><category><![CDATA[General Advice]]></category><dc:creator><![CDATA[Stefan Natter]]></dc:creator><pubDate>Thu, 25 Feb 2021 11:07:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1614235967159/G327WFk4e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As you might know from Catalin's <a target="_blank" href="https://gumroad.com/a/921269363">"Improve Your Online Presence"</a> and Danny Thompson's <a target="_blank" href="https://gumroad.com/a/108459123">"HOW TO GET FOLLOWERS ON TWITTER! How I went from 0 to 30k Followers in 90 Days!"</a> successful Twitter courses already, engagement on Twitter is one of the most important factors for growth. To achieve this engagement there are a couple of ways. For instance, you either interact a lot with your audience, or you post your tweets at the right time.</p>
<p>Both can get you where you want to go. To get a sense of when your audience is most active and engaged, there are several tools. One was recently brought to my attention in one of my Twitter chats <a target="_blank" href="https://studio.twitter.com/audience-insights">the Audience Insights in the Twitter Media Studio</a>.</p>
<h2 id="audience-insights">Audience Insights</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1614235309706/x0ko2-GOM.png" alt="Audience Insights Example" /></p>
<p> As you can see from my example, my audience is more engaged towards the evening. For this reason, I have also timed my tweets for the evening.</p>
<p>What do your audience insights look like? Look at them regularly and take appropriate steps. The best thing about the tool? It's free.</p>
<p>-&gt; <a target="_blank" href="https://studio.twitter.com/audience-insights">https://studio.twitter.com/audience-insights</a></p>
<h2 id="alternative-tool">Alternative Tool</h2>
<p><a target="_blank" href="https://twitter.com/danrot90/status/1366635253079638016">Daniel Rotter made me aware of a tool</a> I use a lot but forgot to mention. 🤦‍♂️</p>
<p>If you cannot access Twitter Audience Insights use the alternative: <a target="_blank" href="https://nttr.st/2PgUpZo">followerwonk</a>.</p>
<h2 id="pro-tip">Pro Tip 🔥</h2>
<p>I have an additional tip for you. So that you don't have to set an alarm clock to send your tweets at the right time, you should use <a target="_blank" href="https://nttr.st/3aSMf20">Feed Hive</a>. I've been using <a target="_blank" href="https://twitter.com/SimonHoiberg">Simon Høiberg</a>'s solution for a while now. I can schedule my week ahead, prepare tweets, have them retweeted automatically, and more. <strong>It's fantastic.</strong> You should definitely check it out and include it in your growth strategy.</p>
<hr />
<h2 id="share">Share 💛</h2>
<p>Do you like this article? Do you want to support me? <a target="_blank" href="https://ctt.ac/_1Pm9">Tell your friends on Twitter</a> about it. Thank you!</p>
<h2 id="questions-and-feedback">Questions and Feedback</h2>
<p>You got any questions or want to add your thoughts? Let me know in the comments below, please.</p>
<h2 id="lets-connect">Let's connect</h2>
<div class="hn-embed-widget" id="newsletter-form"></div><hr />
<p><em>This post includes affiliate links; I may receive compensation if you purchase products or services from the different links provided in this article.</em></p>
]]></content:encoded></item><item><title><![CDATA[Count page views on your GitHub profile with this
one-liner]]></title><description><![CDATA[Ever wonder how often your GitHub profile gets opened? You can enhance your profile with various GitHub actions, images, badges, etc., but you get little to no feedback from GitHub on how often your profile is interacted with or viewed. The same goes...]]></description><link>https://blog.natterstefan.me/count-page-views-on-your-github-profile-with-this-one-liner</link><guid isPermaLink="true">https://blog.natterstefan.me/count-page-views-on-your-github-profile-with-this-one-liner</guid><category><![CDATA[GitHub]]></category><category><![CDATA[analytics]]></category><category><![CDATA[github-actions]]></category><category><![CDATA[#growth]]></category><dc:creator><![CDATA[Stefan Natter]]></dc:creator><pubDate>Wed, 24 Feb 2021 12:22:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1614169340751/925kdDf9d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Ever wonder how often your GitHub profile gets opened? You can enhance your profile <a target="_blank" href="https://blog.natterstefan.me/how-to-present-your-latest-blog-posts-and-youtube-videos-on-your-github-profile">with various GitHub actions</a>, images, badges, etc., but you get little to no feedback from GitHub on how often your profile is interacted with or viewed. The same goes for issues and pull requests, though I'm not sure if a page view counter makes sense there.</p>
<p>Regardless of this, I went in search of a solution for you and found a few. Several one-liners are at your disposal.</p>
<h2 id="how-to-add-a-page-view-counter">How To Add a Page View Counter</h2>
<p>No matter which one you use, they all end up being very similar. With a one-liner, the badge is added and from then on every load of the badge counts as a pageview. So you just have to consider if you think the pageview service will persist, so you do not start from 0 again. But I do not have an answer for that. I have decided on one, and let's see how long that lasts. I use the pageviews on my profile only as an indicator of whether it rises, the absolute number interests me only limited I must say.</p>
<p>On my <a target="_blank" href="https://github.com/natterstefan">GitHub profile</a> you see a page view counter from <a target="_blank" href="https://github.com/antonkomarev/github-profile-views-counter">antonkomarev/github-profile-views-counter</a>. All I had to do, to add it to my profile was adding this line (<em>Note: I also changed the color with <code>&amp;color=&lt;value&gt;</code></em>):</p>
<pre><code class="lang-md">[<span class="hljs-string">![GitHub Views</span>](<span class="hljs-link">https://komarev.com/ghpvc/?username=natterstefan&amp;color=FAC151</span>)][<span class="hljs-symbol">1</span>]
</code></pre>
<p>Now I have a page view counter on my GitHub profile. That's it. You can get your own counter by adding your username.</p>
<pre><code class="lang-md">![<span class="hljs-string">GitHub Views</span>](<span class="hljs-link">https://komarev.com/ghpvc/?username=&lt;username&gt;</span>)
</code></pre>
<p>Thanks, <a target="_blank" href="https://github.com/antonkomarev">Anton Komarev</a> for creating this!</p>
<h2 id="alternatives-and-dyi-solutions">Alternatives and DYI Solutions</h2>
<p>I promised you to present more than one solution because there are several ways to Rome. Here are a few alternatives with the same result.</p>
<ul>
<li><a target="_blank" href="https://yhype.me/">Ÿ HŸPE</a></li>
<li><a target="_blank" href="https://github.com/arturssmirnovs/github-profile-views-counter">arturssmirnovs/github-profile-views-counter</a></li>
<li><a target="_blank" href="https://github.com/jwenjian/visitor-badge">jwenjian/visitor-badge</a></li>
<li><a target="_blank" href="https://dev.to/ryanlanciaux/visitor-count-on-your-github-profile-with-one-line-of-markdown-593g">Add a visitor count on your GitHub profile with one line of Markdown</a></li>
<li>or you create one yourself with the help of this tutorial <a target="_blank" href="https://dev.to/ryanlanciaux/quick-github-profile-visit-counter-14en">Quick GitHub profile visit counter</a></li>
</ul>
<p>Do you use another one? Let me know in the comments below, please. 👇</p>
<hr />
<h2 id="share">Share 💛</h2>
<p>Do you like this article? Do you want to support me? <a target="_blank" href="https://ctt.ac/0bl54">Tell your friends on Twitter</a> about it. <strong>Thank you!</strong></p>
<h2 id="questions-and-feedback">Questions and Feedback</h2>
<p>You got any questions or want to add your thoughts? Let me know in the comments below, please.</p>
<h2 id="lets-connect">Let's connect</h2>
<div class="hn-embed-widget" id="newsletter-form"></div>]]></content:encoded></item><item><title><![CDATA[2 Simple Growth Hacks to Get More Followers on YouTube and Twitter]]></title><description><![CDATA[Content creators place backlinks to their social media profiles and websites in a wide variety of places in their works. This helps you bring new and returning visitors to your owned content. If you are like me, you just took your Twitter profile URL...]]></description><link>https://blog.natterstefan.me/2-simple-growth-hacks-to-get-more-followers-on-youtube-and-twitter</link><guid isPermaLink="true">https://blog.natterstefan.me/2-simple-growth-hacks-to-get-more-followers-on-youtube-and-twitter</guid><category><![CDATA[#growth]]></category><category><![CDATA[product]]></category><category><![CDATA[marketing]]></category><category><![CDATA[Twitter]]></category><category><![CDATA[youtube]]></category><dc:creator><![CDATA[Stefan Natter]]></dc:creator><pubDate>Tue, 23 Feb 2021 11:14:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1614063444315/W5LeIjG6Q.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Content creators place backlinks to their social media profiles and websites in a wide variety of places in their works. This helps you bring new and returning visitors to your owned content. If you are like me, you just took your Twitter profile URL for this (https://twitter.com/natterstefan) in my case) and linked it, for example in the footer of your <a target="_blank" href="https://newsletter.natterstefan.me">newsletter</a>.</p>
<p>So far so good, but did you know that you can go one step further and ask your readers to follow you almost immediately when they click on the link? Isn't that your actual goal and also the intent when they click on the link?</p>
<p>It is a simple change that needs to be done once and results in immediate benefits. I am sure you can benefit from this Growth Hack, that is why I want to share it with you.</p>
<p>Let's take a look at the following example. Do you spot the difference between <a target="_blank" href="https://twitter.com/natterstefan">this link to my Twitter profile</a> and <a target="_blank" href="https://twitter.com/intent/follow?screen_name=natterstefan">this one</a>? If you clicked on the second link you saw a follow popup on Twitter. Cool, isn't it? If not, try it now.</p>
<p>What about YouTube? Which link do you like more: <a target="_blank" href="https://www.youtube.com/natterstefan">this link most people use</a> or <a target="_blank" href="https://www.youtube.com/natterstefan?sub_confirmation=1">this one you going to use from now on</a>?</p>
<h2 id="how-to-implement-it-for-your-site">How To Implement It For Your Site?</h2>
<p>It is actually very simple. This is the link to use this Growth Hack:</p>
<ul>
<li><code>https://twitter.com/intent/follow?screen_name=&lt;username&gt;</code></li>
</ul>
<p>Simply replace <code>username</code> with your username and you are good to go. The link above looks like this:</p>
<ul>
<li><code>https://twitter.com/intent/follow?screen_name=natterstefan</code></li>
</ul>
<p>All you need to do now is updating all your links to your <a target="_blank" href="https://twitter.com/intent/follow?screen_name=natterstefan">Twitter</a> account on your  <a target="_blank" href="https://natterstefan.me">website</a>, <a target="_blank" href="https://blog.natterstefan.me">Blog</a>,  <a target="_blank" href="https://www.youtube.com/natterstefan?sub_confirmation=1">YouTube channel</a>, etc.!</p>
<h2 id="how-to-use-this-on-youtube">How To Use This On YouTube?</h2>
<p>It works similarly on YouTube. Instead of using</p>
<ul>
<li><code>https://www.youtube.com/&lt;channelId&gt;</code></li>
</ul>
<p>you should use this link</p>
<ul>
<li><code>https://www.youtube.com/&lt;channelId&gt;?sub_confirmation=1</code>.</li>
</ul>
<p>The link above for my example looks like this:</p>
<ul>
<li><code>https://www.youtube.com/natterstefan?sub_confirmation=1</code></li>
</ul>
<h2 id="start-growth-hacking-now">Start Growth Hacking Now 🔥</h2>
<p>I hoped you like this simple but effective Growth Hack. If you want more Growth and Productivity Hacks consider subscribing to my <a target="_blank" href="https://newsletter.natterstefan.me">newsletter</a>.</p>
<hr />
<h2 id="share">Share 💛</h2>
<p>Do you like this article? Do you want to support me? <a target="_blank" href="https://ctt.ac/syZIv">Tell your friends on Twitter</a> about it. <strong>Thank you!</strong></p>
<h2 id="questions-and-feedback">Questions and Feedback</h2>
<p>You got any questions or want to add your thoughts? Let me know in the comments below, please.</p>
<h2 id="lets-connect">Let's connect</h2>
<div class="hn-embed-widget" id="newsletter-form"></div>]]></content:encoded></item><item><title><![CDATA[Discover The Benefits You Get With GitHub Templates]]></title><description><![CDATA[Did you know that you can create templates for issues and pull requests on GitHub? This way you can specify how issues and pull requests in open-source projects, but also closed-source ones of your company, have to look like. In my opinion, this has ...]]></description><link>https://blog.natterstefan.me/discover-the-benefits-you-get-with-github-templates</link><guid isPermaLink="true">https://blog.natterstefan.me/discover-the-benefits-you-get-with-github-templates</guid><category><![CDATA[GitHub]]></category><category><![CDATA[Git]]></category><category><![CDATA[Productivity]]></category><dc:creator><![CDATA[Stefan Natter]]></dc:creator><pubDate>Mon, 22 Feb 2021 20:22:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1614025298169/rPYqrsMmt.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Did you know that you can create templates for issues and pull requests on GitHub? This way you can specify how issues and pull requests in open-source projects, but also closed-source ones of your company, have to look like. In my opinion, this has several advantages. In today's article, I'll show you what GitHub templates are, how to create and use them, and what value they add.</p>
<h2 id="what-are-github-templates">What Are GitHub Templates?</h2>
<p>GitHub templates are boilerplates for issues and pull requests that can be selected when creating them. This allows you to create a predefined structure for bug reports, feature requests, and discussions.</p>
<p>I am sure you have noticed that various larger open source projects always have the same structure for issues and pull requests? Let's take a look at <a target="_blank" href="https://editorjs.io/">EditorJS</a> for instance. One of my favorite editors. Whenever you <a target="_blank" href="https://github.com/codex-team/editor.js/issues/new/choose">open an issue</a>, you see this interface:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1614025385268/RmWENGwRN.png" alt="editor.js create issue overview" /></p>
<p>This gives maintainers a clear and structured way to deal with new reports. The structure makes new issues comparable and provides a standardized framework. This also helps more inexperienced issue reporters to mention the essentials and makes it easier for the maintainers to find a solution.</p>
<h2 id="how-to-create-github-templates">How to Create GitHub Templates</h2>
<p>Like many things on GitHub - you can tell I'm a fan - creating templates is not hard. All you need is a <code>.github/ISSUE_TEMPLATE</code> folder where you put the templates.</p>
<p>A very simple and basic template looks like the following example. The <code>name</code> and <code>about</code> metadata are mandatory. But there are others, which we will discuss later.</p>
<pre><code class="lang-md">---
name: Bug report
<span class="hljs-section">about: Create a report to help us improve our package
---</span>

<span class="xml"><span class="hljs-comment">&lt;!-- Enter text here --&gt;</span></span>
</code></pre>
<p>If you save this now as <code>.github/ISSUE_TEMPLATE/bug_report.md</code>, you'd have your first issue template ready.</p>
<p>--&gt; You can read more about how to create them <a target="_blank" href="https://docs.github.com/en/github/building-a-strong-community/about-issue-and-pull-request-templates">in the official docs</a>.</p>
<p>Let's have a look at more examples by looking at <a target="_blank" href="https://github.com/codex-team/editor.js/tree/next/.github/ISSUE_TEMPLATE">EditorJS templates</a> in detail. They have created multiple templates for "Bug report", "Discussion", "Feature request", "Issue: Discussion" and even external links pointing to their Telegram chats. This is their <code>discussions.md</code> template:</p>
<pre><code class="lang-md">---
name: Discussion
about: Any question about the Editor.js to discuss
title: ''
labels: discussion
assignees: ''

---

The question.

Why and how the question has come up.

<span class="xml"><span class="hljs-comment">&lt;!--
🤫 If you like Editor.js, please consider supporting us via OpenCollective:
https://opencollective.com/editorjs
--&gt;</span></span>
</code></pre>
<p>You already know <code>name</code> and <code>about</code>. As you can see, you can also add a default <code>title</code>, add existing <code>labels</code>, and even assign contributors (<code>assignees</code>) already to newly created issues. This can be very helpful when you have one in your team who's responsible for taking the first view at new issues, feature requests, or questions. In the example above you also see that they make use of HTML comments (<code>&lt;!-- (...) --&gt;</code>). Only the creator of the issues see's this comment, or if you edit the issue, but it's not visible to others. You can use this to add additional information or instructions. They used it to promote their OpenCollective link.</p>
<p>Speaking of links, as you can see from the first screenshot of the article, you have also added external links. Let's see how this works. Apparently, it needs the following file for that: <code>.github/ISSUE_TEMPLATE/config.yml</code>.</p>
<pre><code class="lang-yml"><span class="hljs-attr">blank_issues_enabled:</span> <span class="hljs-literal">false</span>
<span class="hljs-attr">contact_links:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Team</span>
    <span class="hljs-attr">url:</span> <span class="hljs-string">mailto:team@codex.so</span>
    <span class="hljs-attr">about:</span> <span class="hljs-string">Direct</span> <span class="hljs-string">team</span> <span class="hljs-string">contact.</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Editor.js</span> <span class="hljs-string">Telegram</span> <span class="hljs-string">chat</span>
    <span class="hljs-attr">url:</span> <span class="hljs-string">https://t.me/codex_editor</span>
    <span class="hljs-attr">about:</span> <span class="hljs-string">Telegram</span> <span class="hljs-string">chat</span> <span class="hljs-string">for</span> <span class="hljs-string">Editor.js</span> <span class="hljs-string">users</span> <span class="hljs-string">communication.</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Editor.js</span> <span class="hljs-string">contributors</span> <span class="hljs-string">Telegram</span> <span class="hljs-string">chat</span>
    <span class="hljs-attr">url:</span> <span class="hljs-string">https://t.me/editorjsdev</span>
    <span class="hljs-attr">about:</span> <span class="hljs-string">Telegram</span> <span class="hljs-string">chat</span> <span class="hljs-string">for</span> <span class="hljs-string">Editor.js</span> <span class="hljs-string">contributors</span> <span class="hljs-string">communication.</span>
</code></pre>
<p>By setting <code>blank_issues_enabled</code> to <code>false</code> your contributors will have to use one of your issue templates. If you set <code>blank_issues_enabled</code> to <code>true</code>, people will have the option to open a blank issue.</p>
<p><code>contact_links</code> contains an array of objects containing <code>name</code>, <code>url</code> and <code>about</code>. This is it, you have now added external links to your GitHub issue templates as well.</p>
<p>--&gt;  <a target="_blank" href="https://docs.github.com/en/github/building-a-strong-community/configuring-issue-templates-for-your-repository#configuring-the-template-chooser">Docs: Configuring the template chooser</a></p>
<p>For pull requests, the whole thing is even simpler. You create <code>.github/PULL_REQUEST_TEMPLATE.md</code> and insert the template structure. As far as I know, no metadata is needed here. So your template can look like this directly:</p>
<pre><code class="lang-md"><span class="hljs-section"># [<span class="hljs-string">STORY</span>](<span class="hljs-link">http://app.clickup.com</span>)</span>

<span class="hljs-section">## What I did</span>

<span class="hljs-section">## How to test</span>

<span class="hljs-section">## Screenshots</span>
</code></pre>
<h2 id="what-is-the-value-of-github-templates">What Is The Value Of GitHub Templates?</h2>
<p>For me, the value of GitHub templates is quite clear and I use them in <a target="_blank" href="https://github.com/natterstefan?tab=repositories&amp;type=source">all my newer public repositories</a>. Providing a structure and support for issue creators is important to me and helps not only them but me as well!</p>
<p>Especially pull request templates, which in my experience are relatively more common in closed source projects, have proven to be very helpful. There may be different opinions on if and how much information the description of a pull request should contain. I believe that the more helpful details the creator adds <em>now</em> - using the template structure - the more helpful it will be in the future when it comes to understanding the context of a change. This has already helped me with one or the other session in the git history. Don't be too lazy to add details. Your future self and colleagues will thank you.</p>
<hr />
<h2 id="share">Share 💛</h2>
<p>Do you like this article? Do you want to support me? <a target="_blank" href="https://ctt.ac/46115">Tell your friends on Twitter</a> about it. Thank you!</p>
<h2 id="questions-and-feedback">Questions and Feedback</h2>
<p>You got any questions or want to add your thoughts? Let me know in the comments below, please.</p>
<h2 id="lets-connect">Let's connect</h2>
<div class="hn-embed-widget" id="newsletter-form"></div>]]></content:encoded></item><item><title><![CDATA[Impress Your Friends By Visualizing Your Contributions on GitHub]]></title><description><![CDATA[GitHub is my go-to tool when it comes to the code I write. I have tried both Bitbucket  and GitLab in the past. Time and time again, I come back to GitHub. May it be because of the UI and UX, I can't get along with the other alternatives. And so I'm ...]]></description><link>https://blog.natterstefan.me/impress-your-friends-by-visualizing-your-contributions-on-github</link><guid isPermaLink="true">https://blog.natterstefan.me/impress-your-friends-by-visualizing-your-contributions-on-github</guid><category><![CDATA[GitHub]]></category><category><![CDATA[Twitter]]></category><category><![CDATA[social media]]></category><category><![CDATA[General Programming]]></category><dc:creator><![CDATA[Stefan Natter]]></dc:creator><pubDate>Sun, 21 Feb 2021 16:21:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1613924415874/2ARYJgrlJ.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>GitHub is my go-to tool when it comes to <a target="_blank" href="https://github.com/natterstefan">the code I write</a>. I have tried both <a target="_blank" href="https://bitbucket.org/">Bitbucket</a>  and <a target="_blank" href="https://about.gitlab.com/">GitLab</a> in the past. Time and time again, I come back to GitHub. May it be because of the UI and UX, I can't get along with the other alternatives. And so I'm happy when I discover new tools that enhance my experience on GitHub. Today I'm going to show you two tools. A Chrome extension and a web app.</p>
<h2 id="visualize-your-github-contributions-with-skyline">Visualize Your GitHub Contributions With Skyline</h2>
<p>I am happy that I found <a target="_blank" href="https://twitter.com/SimonEritsch/status/1362445382517727248">this tweet from my friend Simon</a>, sharing <a target="_blank" href="https://skyline.github.com/">GitHub Skyline</a>. </p>
<p>If you know me, you know that this tool immediately excited me. You enter your GitHub username and you get a skyline with the public contributions presented as skyscrapers. Great idea! It's a fun way to encourage people to have more contributions on GitHub.</p>
<p>What does your skyline look like? Here is my <a target="_blank" href="https://skyline.github.com/natterstefan/2020">GitHub Skyline from 2020</a>. <a target="_blank" href="https://skyline.github.com/natterstefan/2021">2021 is in progress</a>. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613923745748/OQ-3J7wnd.png" alt="GitHub Skyline of natterstefan" /></p>
<h2 id="github-isometric-contributions">GitHub Isometric Contributions</h2>
<p>This is another interesting extension for Chrome. It visualizes your GitHub contributions graph and creates an isometric pixel view of the public data on your profile. Here is mine:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613923908684/_WcYfwaRg.png" alt="GitHub Isometric Contributions - natterstefan" /></p>
<p>--&gt;  <a target="_blank" href="https://chrome.google.com/webstore/detail/github-isometric-contribu/mjoedlfflcchnleknnceiplgaeoegien">Get the Extensions</a></p>
<p>PS: Did you know that you can <a target="_blank" href="https://nttr.st/3dxgVYf">support me on GitHub and become my GitHub sponsor</a>?</p>
<hr />
<h2 id="share">Share 💛</h2>
<p>Do you like this article? Do you want to support me? <a target="_blank" href="https://ctt.ac/JEXad">Tell your friends on Twitter</a> about it. Thank you!</p>
<h2 id="questions-and-feedback">Questions and Feedback</h2>
<p>You got any questions or want to add your thoughts? Let me know in the comments below, please.</p>
<h2 id="lets-connect">Let's connect</h2>
<div class="hn-embed-widget" id="newsletter-form"></div>]]></content:encoded></item><item><title><![CDATA[Why You Should Not Use The Version Tag Or Branch Name When Using GitHub Actions]]></title><description><![CDATA[Malicious code can be inserted into any GitHub action, even those which are tagged.

With these words, Julien Renaux's article titled "Use GitHub actions at your own risk" begins.
Before reading this article from late 2019, I gave little thought to t...]]></description><link>https://blog.natterstefan.me/why-you-should-not-use-the-version-tag-or-branch-name-when-using-github-actions</link><guid isPermaLink="true">https://blog.natterstefan.me/why-you-should-not-use-the-version-tag-or-branch-name-when-using-github-actions</guid><category><![CDATA[GitHub]]></category><category><![CDATA[github-actions]]></category><category><![CDATA[Security]]></category><dc:creator><![CDATA[Stefan Natter]]></dc:creator><pubDate>Sat, 20 Feb 2021 17:32:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1613842212192/QXQBUFnMa.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>Malicious code can be inserted into any GitHub action, even those which are tagged.</p>
</blockquote>
<p>With these words, <a target="_blank" href="https://julienrenaux.fr/2019/12/20/github-actions-security-risk/">Julien Renaux's article titled "Use GitHub actions at your own risk"</a> begins.</p>
<p>Before reading this article from late 2019, I gave little thought to the potential risks from using GitHub Actions (e.g. one that adds <a target="_blank" href="https://blog.natterstefan.me/how-to-present-your-latest-blog-posts-and-youtube-videos-on-your-github-profile">your latest blog posts and YouTube videos to your GitHub profile</a>). I mean doesn't that sound familiar? You search for a certain GitHub action, find the right tutorial, set up the <code>yml</code> file, and stare at the result. How many times have you looked at the source code of the action to see what happens to your data and secrets?</p>
<p>Have you never wondered if your secrets are used elsewhere? There have been similar <a target="_blank" href="https://eslint.org/blog/2018/07/postmortem-for-malicious-package-publishes">scandals with npm packages</a> <a target="_blank" href="https://snyk.io/blog/a-post-mortem-of-the-malicious-event-stream-backdoor/">in the past</a>. It happens again and again that potential malware is infiltrated and no longer does what it promises. This makes it all the more important to pay attention to the security of your data, even with GitHub Actions. How can you do that?</p>
<h2 id="the-problem-maintainers-can-update-tags-and-branches-anytime">The Problem - Maintainers can update tags and branches anytime</h2>
<p>First, let's look at the problem. Tags and releases on GitHub can be deleted and recreated at any time. If you install the innocuous code for v1.2.3 today, the same version number may be infected tomorrow. Julien has drawn attention to this problem in his article. He has also created an <a target="_blank" href="https://github.com/shprink/nonharmful-and-must-have-actions">example repository</a> for it. Okay, now we know the problem. How do we fix it?</p>
<h2 id="the-solution-use-commit-hash-instead-of-release-tags">The Solution - Use commit hash instead of release tags</h2>
<p>Before that, I would like to say something about the following solution. Even if you do this in the future, you need to be aware that it might already contain malicious software. Install GitHub Actions only from trusted developers or look at the source code carefully beforehand.</p>
<p>Okay, so what's the solution?</p>
<p>Instead of using the release tag, or as other GitHub Actions suggest the <code>main</code> branch, <a target="_blank" href="https://nttr.st/3sguBuz">use the commit hash (SHA-1) in the GitHub Action configuration</a>. It is unique and cannot be changed afterward.</p>
<p>Here is an example:</p>
<pre><code class="lang-yml"><span class="hljs-attr">name:</span> <span class="hljs-string">Blog</span> <span class="hljs-string">Posts</span>

<span class="hljs-attr">on:</span>
  <span class="hljs-attr">schedule:</span>
    <span class="hljs-comment"># Runs every hour</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">cron:</span> <span class="hljs-string">'0 * * * *'</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">update-readme-with-blog:</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">Update</span> <span class="hljs-string">this</span> <span class="hljs-string">repo's</span> <span class="hljs-string">README</span> <span class="hljs-string">with</span> <span class="hljs-string">latest</span> <span class="hljs-string">blog</span> <span class="hljs-string">posts</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-comment"># instead of:</span>
      <span class="hljs-comment"># - uses: gautamkrishnar/blog-post-workflow@master</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">gautamkrishnar/blog-post-workflow@94531d3fc177a2753683dc4342c10aa4420fc4f1</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">feed_list:</span> <span class="hljs-string">"https://blog.natterstefan.me/rss.xml"</span>
</code></pre>
<p>Instead of pulling the code from <code>@master</code> I tell GitHub to pull and use <code>@94531d3fc177a2753683dc4342c10aa4420fc4f1</code> instead.</p>
<p>This ensures that you do not install and use a newer version without your knowledge. You have to make a conscious decision to update and you can look at the code beforehand at your leisure. This way you and your data are on the safe side.</p>
<hr />
<h2 id="share">Share 💛</h2>
<p>Do you like this article? Do you want to support me? <a target="_blank" href="https://nttr.st/2ZCspRU">Tell your friends on Twitter</a> about it. Thank you!</p>
<h2 id="questions-and-feedback">Questions and Feedback</h2>
<p>You got any questions or want to add your thoughts? Let me know in the comments below, please.</p>
<h2 id="lets-connect">Let's connect</h2>
<div class="hn-embed-widget" id="newsletter-form"></div>]]></content:encoded></item><item><title><![CDATA[Optimize Your Trello Boards By Adding Members For Specific Card States]]></title><description><![CDATA[Today's tip I got from my friend Manfred and is for all Trello users among you. At my previous company Lovely Systems, we use Trello as a project management tool. All Epics, Stories, and Scrum Plannings took place in and with Trello.
We had a backlog...]]></description><link>https://blog.natterstefan.me/optimize-your-trello-boards-by-adding-members-for-specific-card-states</link><guid isPermaLink="true">https://blog.natterstefan.me/optimize-your-trello-boards-by-adding-members-for-specific-card-states</guid><category><![CDATA[Productivity]]></category><category><![CDATA[project management]]></category><dc:creator><![CDATA[Stefan Natter]]></dc:creator><pubDate>Fri, 19 Feb 2021 17:29:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1613756220350/NYn4ksrVo.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Today's tip I got from my friend Manfred and is for all <a target="_blank" href="https://trello.com/?ref=natterstefan.me">Trello</a> users among you. At my previous company <a target="_blank" href="https://nttr.st/3pyAuS7">Lovely Systems</a>, we use Trello as a project management tool. All Epics, Stories, and Scrum Plannings took place in and with Trello.</p>
<p>We had a backlog list for ideas of any kind, the Epics, a Queue, Working, Review, and Done list. Whoever was responsible for a story had their avatar on the ticket. At a glance, it was quickly visible who was working on what.</p>
<p>But when it came to quickly see the status of a card (e.g. Accepted), Trello's tools were not sufficient.</p>
<p>Trello does have a label system, but they quickly get lost. And so Manfred came up with the idea to create new users and give them a matching status avatar. He created a user for <strong>Estimate</strong>, <strong>Accepted</strong>, <strong>Blocked</strong> and <strong>Question</strong>. These users were used by us and our customers to quickly determine the status of a card.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613755288321/9NzK2b8Gx.png" alt="Example Trello Board" /></p>
<p>A typical flow then looked like this:</p>
<ul>
<li>The PO and the customer created new cards and added the "Estimate" to them.</li>
<li>The team estimated the effort of the card and added the points to the title.</li>
<li>The PO added a developer (e.g. me) to a card in the queue column, when it's ready.</li>
<li>I moved that card to "Working" as soon as I started with it.</li>
<li>Once I had the story of the card implemented, I moved it further to Review and again added the PO or the customer.</li>
<li>When they reviewed the story, they took themself away and added "Accepted" - or "Blocked".</li>
</ul>
<p>This way, we could quickly see at the next scheduled release whether all stories were approved or not.</p>
<p>This has pleasantly expanded the workflow with Trello and made it easier without having to use filters to any great extent.</p>
<p>Do you use Trello? Do you have similar tips and tricks in store? Let me know, please.</p>
<p><em>PS: Now I use <a target="_blank" href="https://nttr.st/3k3WvHv">ClickUp</a></em>.</p>
<hr />
<h2 id="share">Share 💛</h2>
<p>Do you like this article? Do you want to support me? <a target="_blank" href="https://ctt.ac/j9UEf">Tell your friends on Twitter</a> about it. Thank you!</p>
<h2 id="questions-and-feedback">Questions and Feedback</h2>
<p>You got any questions or want to add your thoughts? Let me know in the comments below, please.</p>
<h2 id="lets-connect">Let's connect</h2>
<div class="hn-embed-widget" id="newsletter-form"></div>]]></content:encoded></item><item><title><![CDATA[Delete Unused node_modules From Your Computer Like a Pro With "npkill"]]></title><description><![CDATA[When you execute yarn install or npm install, plenty of node_modules are installed. Your dependencies and devDependencies and their dependencies and so on. So it can quickly happen that the node_modules folder of your project becomes several hundred ...]]></description><link>https://blog.natterstefan.me/delete-unused-nodemodules-from-your-computer-like-a-pro-with-npkill</link><guid isPermaLink="true">https://blog.natterstefan.me/delete-unused-nodemodules-from-your-computer-like-a-pro-with-npkill</guid><category><![CDATA[Node.js]]></category><category><![CDATA[storage]]></category><category><![CDATA[macOS]]></category><category><![CDATA[Windows]]></category><dc:creator><![CDATA[Stefan Natter]]></dc:creator><pubDate>Thu, 18 Feb 2021 07:17:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1613632608970/ACJYz0r32.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When you execute <code>yarn install</code> or <code>npm install</code>, plenty of <code>node_modules</code> are installed. Your <code>dependencies</code> and <code>devDependencies</code> and their <code>dependencies</code> and so on. So it can quickly happen that the <code>node_modules</code> folder of your project becomes several hundred megabytes large. This doesn't sound too bad at first sight, after all, most of us probably have SSDs with &gt;= 500 GB in our laptops and several hard disks in our desktop computers. And yet, excess unused blocked storage space is not an ideal situation. For this reason, I regularly go over my local repositories with <code>npkill</code> and remove all <code>node_modules</code> that are no longer used. I will show you how to do this.</p>
<h2 id="the-solution-npkill">The solution - npkill</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613630508844/C3ZvKtaFP.gif" alt="npkill-demo-0.3.0.gif" /></p>
<blockquote>
<p>Easily find and remove old and heavy node_modules folders ✨</p>
<p>(<a target="_blank" href="https://www.npmjs.com/package/npkill">text and gif source</a>)</p>
</blockquote>
<p>That is exactly what npkill is all about and what it is. It looks for all <code>node_modules</code> (sub-)folders starting at the path where npkill was executed, suggests them for deletion, and removes selected ones when you confirm the selection. This way you can very quickly remove unnecessary clutter. Think of it like <code>docker system prune</code> only for <code>node_modules</code>.</p>
<h2 id="how-to-use-npkill">How to use npkill</h2>
<p>You do not need to install <code>npkill</code> as you can simply start it with:</p>
<pre><code class="lang-bash">npx npkill
</code></pre>
<p>You will see a list of <code>node_modules</code> after it finished the scan. Move up and down with <strong>↓ ↑</strong> and hit <strong>Space</strong> to delete the selected folder. To exit, hit <strong>Q</strong> or <strong>Ctrl + c</strong>. Now you can watch npkill doing its job.</p>
<p>There are more options available, which are listed on <a target="_blank" href="https://www.npmjs.com/package/npkill">the npm page of npkill</a>.</p>
<h2 id="two-more-things">Two more things 🥳</h2>
<p>Whilst doing my research for this article, I stumbled upon some other interesting commands I want to share with you.</p>
<h3 id="how-to-count-installed-packages">How to count installed packages</h3>
<p>Do you know how many packages you have installed for your app? I didn't and was surprised about the result when I used this command.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># https://stackoverflow.com/a/57109195/1238150</span>
npm ls | sed <span class="hljs-string">'/deduped$/d'</span> | wc -l
</code></pre>
<p>If you want to know more about this complex command, take a look at <a target="_blank" href="https://explainshell.com/explain?cmd=npm+ls+%7C+sed+%27%2Fdeduped%24%2Fd%27+%7C+wc+-l">the explanation on explainshell.com</a>.</p>
<h3 id="how-to-find-unused-packages-in-your-packagejson">How to find unused packages in your package.json</h3>
<p>I found this tool called <a target="_blank" href="https://www.npmjs.com/package/depcheck">Depcheck</a> that is a tool for</p>
<blockquote>
<p>(...) analyzing the dependencies in a project to see: how each dependency is used, which dependencies are useless, and which dependencies are missing from package.json.</p>
</blockquote>
<p>Similar to <code>npkill</code> you can run it without installing:</p>
<pre><code class="lang-bash">npx depcheck
</code></pre>
<hr />
<h2 id="share">Share 💛</h2>
<p>Do you like this article? Do you want to support me? <a target="_blank" href="https://ctt.ac/S7Xd7">Tell your friends on Twitter</a> about it. Thank you!</p>
<h2 id="questions-and-feedback">Questions and Feedback</h2>
<p>You got any questions or want to add your thoughts? Let me know in the comments below, please.</p>
<h2 id="lets-connect">Let's connect</h2>
<div class="hn-embed-widget" id="newsletter-form"></div>]]></content:encoded></item><item><title><![CDATA[These 6 Alfred Workflows Can Help You Increase Your Productivity]]></title><description><![CDATA[Alfred has increased my productivity by large ever since I installed it. It has replaced the default Spotlight search of macOS and is my helper whenever I need it. With a few keyboard shortcuts, I get fake data for my apps, shorten links, check out b...]]></description><link>https://blog.natterstefan.me/these-6-alfred-workflows-can-help-you-increase-your-productivity</link><guid isPermaLink="true">https://blog.natterstefan.me/these-6-alfred-workflows-can-help-you-increase-your-productivity</guid><category><![CDATA[Productivity]]></category><category><![CDATA[macOS]]></category><dc:creator><![CDATA[Stefan Natter]]></dc:creator><pubDate>Wed, 17 Feb 2021 07:10:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1613545760604/xA2l247q0.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Alfred has increased my productivity by large ever since I installed it. It has replaced the default Spotlight search of macOS and is my helper whenever I need it. With a few keyboard shortcuts, I get fake data for my apps, shorten links, check out books on Goodreads, <a target="_blank" href="https://nttr.st/3psql9B">need help with JavaScript</a>, and more. It’s fantastic.</p>
<p>I promised <a target="_blank" href="https://twitter.com/natterstefan/status/1361240819596890113">Chris and Bruno on Twitter</a> the other day that I would show them more of my workflows and try to convince them to buy Alfred's Powerpack. Today I'll show you an excerpt from my 50+ workflows. Start small first.</p>
<p>The list of workflows I have today is a mix of productivity tools for Web Developers and Mac Users in general. All you need is <a target="_blank" href="http://www.alfredapp.com/">Alfred</a> and as I said <a target="_blank" href="https://www.alfredapp.com/powerpack/">Alfred’s Powerpack</a>. Let's go!</p>
<h2 id="alfred-workflows">Alfred Workflows</h2>
<h3 id="bitly-url-shortener">Bitly URL Shortener</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613545880479/g3sKX3Krl.gif" alt="Bitly URL Shortener Workflow" /></p>
<p>Attentive readers and Twitter followers may have noticed that I have my own short domain: <a target="_blank" href="https://nttr.st/">nttr.st</a>. This points to Bitly, which I use as a URL shortener service. With this workflow, I create short links without visiting Bitly. All you have to do is install the workflow, insert your <a target="_blank" href="https://bitly.is/accesstoken">Bitly Access Token</a> and you're good to go.</p>
<p>-&gt;  <a target="_blank" href="https://github.com/GimmyHchs/alfred-workflow-bitly">Get the Workflow</a></p>
<h3 id="can-i-use">Can I Use</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613545235890/awstdILnX.png" alt="Can I Use Workflow" /></p>
<p>Can I use this feature in Safari (the new IE)? I have asked this workflow many times and was promptly directed to the appropriate CanIUse page.</p>
<p>-&gt;  <a target="_blank" href="https://github.com/ibnuh/alfred-character-counter-workflow">Get the Workflow</a></p>
<h3 id="lorem-ipsum">Lorem Ipsum</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613545419385/ANd3kL-Ju.gif" alt="Lorem Ipsum Workflow" /></p>
<p>This is definitely one of my most used workflows. How often do you need a placeholder text? With this workflow, I have one right away.</p>
<p>-&gt; <a target="_blank" href="https://github.com/raarellano/alfred-lorem-ipsum-workflow">Get the Workflow</a></p>
<h3 id="refresh-wifi">Refresh Wifi</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613545446787/6h2-P8n-2.png" alt="Refresh Wifi Workflow" /></p>
<p>"Have you ever turned your WiFi off and on again?" this question is not as classic as the one with the computer restart, but nevertheless this skill has already solved one or the other network problem for me. With a few taps on the keyboard, the WiFi is first turned off and then turned on again.</p>
<p>-&gt; <a target="_blank" href="https://www.packal.org/workflow/refresh-wifi">Get the Workflow</a></p>
<h3 id="shush">Shush!</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613545524574/6M0199OOL.png" alt="Shush! Workflow" /></p>
<p>Meetings on Zoom and Co. are no longer a rarity. Every day I spend time in various apps to see my work colleagues, customers, and friends. Some have easy to remember shortcuts to mute the microphone, others do not. The problem is that they all use different shortcuts to quickly mute themselves. That's why this skill is very helpful for me. With my own keyword, I can now toggle the microphone. A tip if you use this workflow, check out <a target="_blank" href="https://github.com/dpskvn/alfred-shush/issues/1#issuecomment-663229760">this issue</a> to fix a volume issue.</p>
<p>-&gt; <a target="_blank" href="https://www.packal.org/workflow/shush-mute-your-microphone">Get the Workflow</a></p>
<hr />
<h2 id="share">Share 💛</h2>
<p>Do you like this article? Do you want to support me? <a target="_blank" href="https://ctt.ac/dxjHF">Tell your friends on Twitter</a> about it. Thank you!</p>
<h2 id="questions-and-feedback">Questions and Feedback</h2>
<p>You got any questions or want to add your thoughts? Let me know in the comments below, please.</p>
<h2 id="lets-connect">Let's connect</h2>
<div class="hn-embed-widget" id="newsletter-form"></div>]]></content:encoded></item><item><title><![CDATA[How to Quickly Transform Tailwind Components into JSX]]></title><description><![CDATA[Have you ever seen a Tailwind component you wanted to use in your React app, but it was only available as plain HTML? You then painstakingly rewrote the HTML so that you can use it in React (e.g. class => className)? That's over now! You can transfor...]]></description><link>https://blog.natterstefan.me/how-to-quickly-transform-tailwind-components-into-jsx</link><guid isPermaLink="true">https://blog.natterstefan.me/how-to-quickly-transform-tailwind-components-into-jsx</guid><category><![CDATA[Tailwind CSS]]></category><category><![CDATA[Tailwind CSS Tutorial]]></category><category><![CDATA[React]]></category><category><![CDATA[JSX]]></category><dc:creator><![CDATA[Stefan Natter]]></dc:creator><pubDate>Tue, 16 Feb 2021 20:50:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1613508532938/bJ3cjs5FF.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Have you ever seen a Tailwind component you wanted to use in your React app, but it was only available as plain HTML? You then painstakingly rewrote the HTML so that you can use it in React (e.g. <code>class</code> =&gt; <code>className</code>)? That's over now! You can transform (almost) any HTML of Tailwind components into a JSX DOM with a few clicks and copy 'n paste. I'll show you how to do that now.</p>
<h2 id="html-of-a-tailwind-component">HTML of a Tailwind Component</h2>
<p>To do this we need a Tailwind component. Let's take an example from <a target="_blank" href="https://play.tailwindcss.com/">Tailwind Playground</a>. The component that is presented looks like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613506982997/b3eh1OH5a.png" alt="Tailwind Component Example" /></p>
<p>This is the associated HTML:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"min-h-screen bg-gray-100 py-6 flex flex-col justify-center sm:py-12"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"relative py-3 sm:max-w-xl sm:mx-auto"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"absolute inset-0 bg-gradient-to-r from-cyan-400 to-light-blue-500 shadow-lg transform -skew-y-6 sm:skew-y-0 sm:-rotate-6 sm:rounded-3xl"</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">"relative px-4 py-10 bg-white shadow-lg sm:rounded-3xl sm:p-20"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"max-w-md mx-auto"</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">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/img/logo.svg"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h-7 sm:h-8"</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">"divide-y divide-gray-200"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"py-8 text-base leading-6 space-y-4 text-gray-700 sm:text-lg sm:leading-7"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>An advanced online playground for Tailwind CSS, including support for things like:<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"list-disc space-y-2"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex items-start"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h-6 flex items-center sm:h-7"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex-shrink-0 h-5 w-5 text-cyan-500"</span> <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 0 20 20"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"currentColor"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">path</span> <span class="hljs-attr">fill-rule</span>=<span class="hljs-string">"evenodd"</span> <span class="hljs-attr">d</span>=<span class="hljs-string">"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"</span> <span class="hljs-attr">clip-rule</span>=<span class="hljs-string">"evenodd"</span> /&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">svg</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">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"ml-2"</span>&gt;</span>
                  Customizing your
                  <span class="hljs-tag">&lt;<span class="hljs-name">code</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-sm font-bold text-gray-900"</span>&gt;</span>tailwind.config.js<span class="hljs-tag">&lt;/<span class="hljs-name">code</span>&gt;</span> file
                <span class="hljs-tag">&lt;/<span class="hljs-name">p</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">"flex items-start"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h-6 flex items-center sm:h-7"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex-shrink-0 h-5 w-5 text-cyan-500"</span> <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 0 20 20"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"currentColor"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">path</span> <span class="hljs-attr">fill-rule</span>=<span class="hljs-string">"evenodd"</span> <span class="hljs-attr">d</span>=<span class="hljs-string">"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"</span> <span class="hljs-attr">clip-rule</span>=<span class="hljs-string">"evenodd"</span> /&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">svg</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">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"ml-2"</span>&gt;</span>
                  Extracting classes with
                  <span class="hljs-tag">&lt;<span class="hljs-name">code</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-sm font-bold text-gray-900"</span>&gt;</span>@apply<span class="hljs-tag">&lt;/<span class="hljs-name">code</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">p</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">"flex items-start"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h-6 flex items-center sm:h-7"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex-shrink-0 h-5 w-5 text-cyan-500"</span> <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 0 20 20"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"currentColor"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">path</span> <span class="hljs-attr">fill-rule</span>=<span class="hljs-string">"evenodd"</span> <span class="hljs-attr">d</span>=<span class="hljs-string">"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"</span> <span class="hljs-attr">clip-rule</span>=<span class="hljs-string">"evenodd"</span> /&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">svg</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">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"ml-2"</span>&gt;</span>Code completion with instant preview<span class="hljs-tag">&lt;/<span class="hljs-name">p</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>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Perfect for learning how the framework works, prototyping a new idea, or creating a demo to share online.<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">"pt-6 text-base leading-6 font-bold sm:text-lg sm:leading-7"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Want to dig deeper into Tailwind?<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://tailwindcss.com/docs"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-cyan-600 hover:text-cyan-700"</span>&gt;</span> Read the docs <span class="hljs-symbol">&amp;rarr;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
            <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>&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>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>As you may realize or know at first glance, we can't use this HTML directly in React. This is because React uses <code>className</code> instead of <code>class</code> among other things. So now let's look at how you can still get components - at least a first draft - into the React world in just a few simple steps.</p>
<h2 id="transformtools">transform.tools</h2>
<p>To achieve this we use the incredible website <a target="_blank" href="https://nttr.st/3aso8qG">transform.tools</a>! On this site, you can transform among other things HTML to JSX.</p>
<p>Open the site, navigate to <a target="_blank" href="https://nttr.st/3dgUWVi">HTML to JSX</a> and copy 'n' paste the HTML of the Tailwind component into the HTML area on the left. The result then looks something like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613507358015/ykEbm6HmK.png" alt="HTML to JSX transformation on transform.tools" /></p>
<p>All you have to do now is simply copying the JSX output on the right into your React app and open your app in the browser. </p>
<p>And lo and behold, our component already looks almost like the one in the example. All you have to do now is to insert the source of the image correctly, adjust it here and there and you are done. But I leave that to you. 😄</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613507432644/T6ZQiN_1p.png" alt="JSX Result" /></p>
<hr />
<h2 id="share">Share 💛</h2>
<p>Do you like this article? Do you want to support me? <a target="_blank" href="https://ctt.ac/Ee8WQ">Tell your friends on Twitter</a> about it. Thank you!</p>
<h2 id="questions-and-feedback">Questions and Feedback</h2>
<p>You got any questions or want to add your thoughts? Let me know in the comments below, please.</p>
<h2 id="lets-connect">Let's connect</h2>
<div class="hn-embed-widget" id="newsletter-form"></div>]]></content:encoded></item><item><title><![CDATA[The One Thing You Need to Do, to Avoid Speeding Tickets. [iOS]]]></title><description><![CDATA[Sooner or later they will get you. You drive too fast and bang, there is an expensive photo of you. I'll show you a simple iOS hack today to avoid getting speeding tickets. All you need is an iPhone, an app that warns you about speed cameras, and the...]]></description><link>https://blog.natterstefan.me/the-one-thing-you-need-to-do-to-avoid-speeding-tickets-ios</link><guid isPermaLink="true">https://blog.natterstefan.me/the-one-thing-you-need-to-do-to-avoid-speeding-tickets-ios</guid><category><![CDATA[iOS]]></category><dc:creator><![CDATA[Stefan Natter]]></dc:creator><pubDate>Mon, 15 Feb 2021 18:58:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1613415466929/t_o-c7CvL.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="hn-embed-widget" id="newsletter-form"></div><p>Sooner or later they will get you. You drive too fast and bang, there is an expensive photo of you. I'll show you a simple iOS hack today to avoid getting speeding tickets. All you need is an iPhone, an app that warns you about speed cameras, and the iOS Shortcuts app. </p>
<p><em>FTR:</em> Sorry Android users. I don't have an Android phone but I'm sure it works there somehow. Feel free to add the "How to" for Android in the comments below!</p>
<hr />
<p><em>Please drive carefully and follow the traffic rules. This article is <strong>not</strong> intended to encourage you to drive faster. It is only meant to inform you how to use iOS shortcuts. Use this tip at your own risk.</em></p>
<hr />
<h2 id="install-a-speed-camera-warning-app">Install a Speed Camera Warning App</h2>
<p>First, we install a speed camera warning app from the App Store. I use <a target="_blank" href="https://nttr.st/3qmZBso">Blitzer.de</a> for this. The app works great in Austria, Switzerland, and Germany. There is a free and a paid version for a few Euros. In this case, it is a good investment.</p>
<h2 id="setup-ios-shortcut">Setup iOS Shortcut</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613414830230/XXfAVkWKe.png" alt="Setup iOS Shortcut - Step 1" /></p>
<p>Open the <a target="_blank" href="https://support.apple.com/guide/shortcuts/welcome/ios">Shortcuts</a> app on the iPhone and select <strong>Automation</strong> in the bottom menu. Press the <strong>plus symbol</strong> in the upper right corner, select <strong>Create Personal Automation</strong>, and <strong>search for CarPlay</strong>. We want the shortcut to be executed whenever the Phone connects with CarPlay.</p>
<p>Now you should see the <strong>Actions screen</strong> with an <strong>Add Action</strong> button. <strong>Press the button</strong> and <strong>search for Open App</strong>. You will come back to the Actions overview screen. Click on the blue <strong>Choose</strong> text and select your speed camera warning app. Press <strong>Next</strong> in the upper right corner, <strong>deactivate Ask Before Running</strong> and press <strong>Done</strong>. That's it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613414910892/Zjp1fULWF.png" alt="Setup iOS Shortcut - Step 2" /></p>
<p>In the future, your iPhone will automatically start the app when you connect it to CarPlay. Simply unlock the phone when you connect your phone so it can start the automation.</p>
<p>You don't have to remember to open your speed camera warning app - iOS does it for you.</p>
<h2 id="questions-and-feedback">Questions and Feedback</h2>
<p>You got any questions or want to add your thoughts? Let me know in the comments below, please.</p>
<h2 id="lets-connect">Let's connect</h2>
<div class="hn-embed-widget" id="newsletter-form"></div>]]></content:encoded></item><item><title><![CDATA[[Pro Tip] How to Validate and Debug Twitter Cards, LinkedIn and Facebook Posts]]></title><description><![CDATA[Content creators produce content with a lot of love. We put a lot of work into the details, the overall picture, and the concept and hope to create value for others with our result. It can be all the more annoying when the Twitter card doesn't look a...]]></description><link>https://blog.natterstefan.me/pro-tip-how-to-validate-and-debug-twitter-cards-linkedin-and-facebook-posts</link><guid isPermaLink="true">https://blog.natterstefan.me/pro-tip-how-to-validate-and-debug-twitter-cards-linkedin-and-facebook-posts</guid><category><![CDATA[Twitter]]></category><category><![CDATA[LinkedIn]]></category><category><![CDATA[Facebook]]></category><dc:creator><![CDATA[Stefan Natter]]></dc:creator><pubDate>Sun, 14 Feb 2021 09:19:57 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1613206241223/lq5un2pXu.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Content creators produce content with a lot of love. We put a lot of work into the details, the overall picture, and the concept and hope to create value for others with our result. It can be all the more annoying when the Twitter card doesn't look as hoped or the Facebook post shows outdated information when sharing the link. Fortunately, there is a solution for this!</p>
<p>The principle is the same on all platforms. You open the validator page, paste your link and press the validate button. Then you will see the result a few seconds later. You are presented with the current version that the platform - e.g. Twitter - has cached. Generally, the check with the validator triggers new indexing and creates a new cache entry. So you have 2-in-1 debugging and cache invalidation with one click.</p>
<p>Here are the links to the validators of Twitter, LinkedIn, and Facebook.</p>
<h2 id="twitter">Twitter</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613198674327/a6OTxnRBE.png" alt="Twitter Card Validator" /></p>
<p>-&gt; URL: https://cards-dev.twitter.com/validator</p>
<p>Are you on Twitter? Let's <a target="_blank" href="https://twitter.com/intent/follow?screen_name=natterstefan">connect</a>!</p>
<h2 id="linkedin">LinkedIn</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613199552707/g4L1tFsam.png" alt="LinkedIn Post Inspector" /></p>
<p>-&gt; URL: https://www.linkedin.com/post-inspector/</p>
<p>Do you have a profile on LinkedIn? Then let's <a target="_blank" href="https://www.linkedin.com/in/natterstefan">connect</a>!</p>
<h2 id="facebook">Facebook</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613230951843/L2aToqyQW.png" alt="Facebook Sharing Debugger" /></p>
<p>-&gt; URL: https://developers.facebook.com/tools/debug/</p>
<h2 id="questions-and-feedback">Questions and Feedback</h2>
<p>You got any questions or want to add your thoughts? Let me know in the comments below, please.</p>
<h2 id="you-want-productivity-and-dev-hacks">You want Productivity and Dev Hacks? 👇🏻</h2>
<div class="hn-embed-widget" id="newsletter-form"></div>]]></content:encoded></item><item><title><![CDATA[How to redirect one Domain to Another with Cloudflare explained.]]></title><description><![CDATA[Up until a few days ago, I did not know you can manage URL and domain redirects and forwarding directly in the Cloudflare dashboard. Other domain name registrars and web hosting companies can do this too (eg. name.com), but I did not know how to mana...]]></description><link>https://blog.natterstefan.me/how-to-redirect-one-domain-to-another-with-cloudflare-explained</link><guid isPermaLink="true">https://blog.natterstefan.me/how-to-redirect-one-domain-to-another-with-cloudflare-explained</guid><category><![CDATA[cloudflare]]></category><category><![CDATA[SEO]]></category><dc:creator><![CDATA[Stefan Natter]]></dc:creator><pubDate>Sat, 13 Feb 2021 06:18:46 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1613197105364/OvMo_Cds7.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Up until a few days ago, I did not know you can manage URL and domain redirects and forwarding directly in the <a target="_blank" href="https://nttr.st/3rRIFLc">Cloudflare dashboard</a>. Other domain name registrars and web hosting companies can do this too (eg. <a target="_blank" href="https://nttr.st/37880Z2">name.com</a>), but I did not know how to manage this in Cloudflare. Maybe you don’t know either and that is why this post exists. Let me show you.</p>
<h2 id="scenario">Scenario</h2>
<p>Let’s assume you want to redirect from <code>old-domain.com</code> to <code>new-domain.com</code>.</p>
<h3 id="step-1-update-dns-settings">Step 1 — Update DNS Settings</h3>
<p>First, make sure you manage the domain you want to redirect from on Cloudflare. Next thing you do is adding the following DNS settings:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613196754644/3esLBigN9.png" alt="Update DNS Settings" /></p>
<p>In this case, we redirect the root (<code>@</code>) and www of the domain. Point it to a dummy domain, in this case, <code>192.1.2.3</code> (got this from <a target="_blank" href="https://community.cloudflare.com/t/redirecting-one-domain-to-another/81960?ref=natterstefan.me">here</a>). It’s important that you set the proxy status to <code>Proxied</code>.</p>
<h3 id="step-2-set-up-page-rules">Step 2 — Set up Page Rules</h3>
<p>Finally, we add a redirect <a target="_blank" href="https://support.cloudflare.com/hc/en-us/articles/218411427-Understanding-and-Configuring-Cloudflare-Page-Rules-Page-Rules-Tutorial-">page rule</a>. When you are not sure which status code fits, read <a target="_blank" href="https://www.searchenginejournal.com/301-vs-302-redirects-seo/299843/">“301 vs. 302 Redirects &amp; SEO: The What, Why &amp; How”</a> on searchenginejournal.com.</p>
<p>In this example, every hit on the old domain (no matter if you open the site with or without <code>www</code> or with <code>https</code> or <code>http</code>) is redirected to the new one.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613196775068/YriXho04_.png" alt="Set up Page Rules" /></p>
<p>What does this page rule do now? If the URL matches it will forward the browser to the new target. The following examples will be redirected:</p>
<ul>
<li><code>old-domain.com</code> =&gt; <code>https://new-domain.com</code></li>
<li><code>www.old-domain.com</code> =&gt; <code>https://new-domain.com</code></li>
<li><code>old-domain.com/hello</code> =&gt; <code>https://new-domain.com/hello</code></li>
<li><code>www.old-domain.com/hello</code> =&gt; <code>https://new-domain.com/hello</code></li>
</ul>
<p>That’s it. You successfully redirected a domain to another with Cloudflare. Congrats!</p>
]]></content:encoded></item><item><title><![CDATA[Who Else Wants an Easy To use Color Picker for macOS?]]></title><description><![CDATA[Have you ever been in that situation that you see a great color and want to have the color code? This happens to me very often. I used to open the Developer Tools in the browser or Photoshop to inspect the color. But that is and was cumbersome. It co...]]></description><link>https://blog.natterstefan.me/who-else-wants-an-easy-to-use-color-picker-for-macos</link><guid isPermaLink="true">https://blog.natterstefan.me/who-else-wants-an-easy-to-use-color-picker-for-macos</guid><category><![CDATA[macOS]]></category><category><![CDATA[Productivity]]></category><category><![CDATA[color]]></category><category><![CDATA[life-hack]]></category><dc:creator><![CDATA[Stefan Natter]]></dc:creator><pubDate>Fri, 12 Feb 2021 06:53:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1613113325927/ACV0DAtt1.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Have you ever been in that situation that you see a great color and want to have the color code? This happens to me very often. I used to open the Developer Tools in the browser or Photoshop to inspect the color. But that is and was cumbersome. It could be easier, I thought, and went in search of a color picker.</p>
<h2 id="colorslourp">ColorSlourp</h2>
<p>Attentive readers of <a target="_blank" href="https://nttr.st/2ZcCi8R">my newsletter</a> already know this tool. I mentioned it in my 31st edition of the newsletter - <a target="_blank" href="https://nttr.st/2MQtl2A">ColorSlourp</a>. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613111801312/Aexam7BVP.png" alt="ColorSlourp" /></p>
<p>ColorSlourp can be installed and used free of charge. It has a PRO version with various features, but so far I haven't needed it. I just want to get to colors quickly.</p>
<p>Once installed, you only have to open the tool and select the pipette. You will immediately see the various color codes (e.g. RGB) when you hover over various elements on your screen. A click on the element copies the displayed code into your clipboard. From then on you can continue to use it. This is very quick and incredibly practical.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613112489679/U5MDMF4xA.gif" alt="How to use ColorSlourp" /></p>
<p>There are certainly other tools besides ColorSlourp, such as <a target="_blank" href="https://nttr.st/3jE7jMk">Sip</a>. I have not tested other alternatives yet, as this tool is sufficient for my use cases. What about you? Which other color pickers have you already tried and can you recommend?</p>
<h2 id="you-want-more-productivity-hacks">You want more Productivity Hacks 👇🏻?</h2>
<div class="hn-embed-widget" id="newsletter-form"></div>]]></content:encoded></item><item><title><![CDATA[How to use shared settings and recommended extensions in a team in VS Code.]]></title><description><![CDATA[There is no question that Visual Studio Code is one of the most popular IDEs for JavaScript developers. It has proven to be quite robust, extensible, and adjustable. There are several ways to tailor the editor to one's own needs. Be it with extension...]]></description><link>https://blog.natterstefan.me/how-to-use-shared-settings-and-recommended-extensions-in-a-team-in-vs-code</link><guid isPermaLink="true">https://blog.natterstefan.me/how-to-use-shared-settings-and-recommended-extensions-in-a-team-in-vs-code</guid><category><![CDATA[Visual Studio Code]]></category><category><![CDATA[Productivity]]></category><category><![CDATA[team]]></category><category><![CDATA[Company]]></category><dc:creator><![CDATA[Stefan Natter]]></dc:creator><pubDate>Thu, 11 Feb 2021 07:25:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1613028406784/-ZnQw8vUq.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There is no question that Visual Studio Code is one of the most popular IDEs for JavaScript developers. It has proven to be quite robust, extensible, and adjustable. There are several ways to tailor the editor to one's own needs. Be it with <a target="_blank" href="https://blog.natterstefan.me/make-console-logging-in-vs-code-10x-faster-with-turbo-console-log">extensions</a>, <a target="_blank" href="https://blog.natterstefan.me/how-to-add-custom-code-snippets-in-vs-code">code snippets</a>, or shortcuts - you can make it your editor.</p>
<p>And that is precisely where the problem lies from time to time. Especially when working in teams. Some of your teammates may not have <a target="_blank" href="https://prettier.io/">Prettier</a> installed and keep sending you strangely formatted code. Others may not use <a target="_blank" href="https://stylelint.io/">Stylelint</a> and don't know the dos and don'ts of CSS, which it recognizes. All this can lead to frustration, especially for the architects of the repository and project. After all, they put a lot of thought into the setup.</p>
<p>For this reason, I will show you today how you can use the <code>.vscode</code> settings folder to give your workspace a uniform basis and avoid certain problems, or at least point them out to contributor.</p>
<h2 id="vscode"><code>.vscode</code></h2>
<p>You may have seen the folder a time or two in repositories: <code>.vscode</code>. In short, this folder contains the settings that VS Code applies to this workspace.</p>
<blockquote>
<p>A VS Code "workspace" is usually just your project root folder. Workspace settings as well as debugging and task configurations are stored at the root in a .vscode folder.
(<a target="_blank" href="https://code.visualstudio.com/docs/getstarted/settings">source</a>)</p>
</blockquote>
<p>This means that this folder will not change your general user settings, only the settings of the current workspace. Even though many developers add the folder to the <code>.gitignore</code>, I am increasingly deviating from this and check in the folder to ensure clarity in teams.</p>
<p><em>FTR: I know there is <a target="_blank" href="https://editorconfig.org/?ref=natterstefan.me">another standard to configure editors</a> with <code>.editorconfig</code>, but I'll focus on VS Code in this article.
</em></p>
<p>Here is a rough overview of the files you can store in the folder:</p>
<ul>
<li>Editor and extension settings for linters and code formatting tools to enforce the code style used in this repo -&gt; <code>settings.json</code> (<a target="_blank" href="https://nttr.st/2Z2nGZw">docs</a>)</li>
<li>Run and debug configurations -&gt; <code>launch.json</code> (<a target="_blank" href="https://nttr.st/3aRecWF">docs</a>)</li>
<li>Shared tasks managed with VS Code -&gt; <code>tasks.json</code> (<a target="_blank" href="https://nttr.st/374WLAR">docs</a>)</li>
<li>Recommended list of extensions for the workspace -&gt; <code>extensions.json</code> (<a target="_blank" href="https://nttr.st/3tMS7RB">docs</a>)</li>
</ul>
<p>I'll focus on <code>settings.json</code> and <code>extensions.json</code> for now and cover the other ones in a follow-up article.</p>
<h3 id="example-settingsjson">Example <code>settings.json</code></h3>
<pre><code class="lang-json">{
   <span class="hljs-attr">"editor.rulers"</span>: [
     <span class="hljs-number">80</span>,
   ],
  <span class="hljs-attr">"editor.tabSize"</span>: <span class="hljs-number">2</span>,
  <span class="hljs-attr">"editor.insertSpaces"</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">"files.eol"</span>: <span class="hljs-string">"\n"</span>
}
</code></pre>
<p>This is an excerpt of a <code>settings.json</code>, which I now continuously add to projects. It ensures in this case that spaces, a tab size of 2, and <code>lf</code> as the end of line setting are used. Additionally, a ruler is shown at 80 chars to visualize the maximum width a line should have. As soon as someone opens the editor these settings get applied. This is very helpful to have a clear and common understanding of certain rules.</p>
<h3 id="example-extensionsjson">Example <code>extensions.json</code></h3>
<pre><code class="lang-json">{
  <span class="hljs-attr">"recommendations"</span>: [
    <span class="hljs-string">"bradlc.vscode-tailwindcss"</span>,
    <span class="hljs-string">"dbaeumer.vscode-eslint"</span>,
    <span class="hljs-string">"eamodio.gitlens"</span>,
    <span class="hljs-string">"esbenp.prettier-vscode"</span>,
    <span class="hljs-string">"pflannery.vscode-versionlens"</span>,
    <span class="hljs-string">"stylelint.vscode-stylelint"</span>,
    <span class="hljs-string">"syler.sass-indented"</span>,
    <span class="hljs-string">"wayou.vscode-todo-highlight"</span>,
    <span class="hljs-string">"ziyasal.vscode-open-in-github"</span>,
  ]
}
</code></pre>
<p>This file is definitely one of my favorites: suggest extensions for a workspace.</p>
<p>I am often asked by colleagues "Which extension do you use here? Why is it automatic for you?" - and that is exactly where the <code>extension.json</code> is helpful. Once added, it suggests extensions to every developer that has not yet been installed. One-click on "Install" and the suggested extensions are installed. You can find a list of the extensions I have installed <a target="_blank" href="https://nttr.st/3aXzAJR">here</a>.</p>
<p>There are several ways to add an extension to the file. Either you go to the <a target="_blank" href="https://nttr.st/2TEyqfO">VS Code Marketplace and copy the ID of the extension</a> next to its name, or get it from within your VS Code. Open the Command Palette -&gt; select <strong>Extensions: Show Installed Extensions</strong> -&gt; find the extension and open the context menu -&gt; select <strong>Add to Workspace Recommendations</strong>).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613027532013/NRQhiezeK.png" alt="How to add a VS Code extension to extensions.json" /></p>
<p>That's it. Now you have a base foundation for working in a team.</p>
<h2 id="questions-and-feedback">Questions and Feedback</h2>
<p>Do you use these files too? What settings have you agreed on? Let me know in the comments below.</p>
<h2 id="lets-connect">Let's connect</h2>
<div class="hn-embed-widget" id="newsletter-form"></div>]]></content:encoded></item></channel></rss>