<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gökay Okyay</title>
    <description>The latest articles on DEV Community by Gökay Okyay (@gokayokyay).</description>
    <link>https://dev.to/gokayokyay</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F284909%2Facc686fe-f483-4470-a26a-a4700c492524.jpg</url>
      <title>DEV Community: Gökay Okyay</title>
      <link>https://dev.to/gokayokyay</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gokayokyay"/>
    <language>en</language>
    <item>
      <title>Build your own React CI in 5 minutes!</title>
      <dc:creator>Gökay Okyay</dc:creator>
      <pubDate>Fri, 07 May 2021 23:11:22 +0000</pubDate>
      <link>https://dev.to/gokayokyay/build-your-own-react-ci-in-5-minutes-1aen</link>
      <guid>https://dev.to/gokayokyay/build-your-own-react-ci-in-5-minutes-1aen</guid>
      <description>&lt;p&gt;Hey everyone! This post is part of &lt;em&gt;Introduction to StewardX&lt;/em&gt; series.&lt;/p&gt;

&lt;p&gt;In this tutorial, I'll show you how can you build your own CI, super easy.&lt;/p&gt;

&lt;p&gt;All you need is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/gokayokyay/stewardx"&gt;StewardX&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A Linux server (preferably with sudo access)&lt;/li&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;NodeJS - for building React of course 😊&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My server's OS is Debian flavored (Ubuntu) but you should be able to find the installation commands of the packages for your own distribution just by a quick search, if not please leave a comment so I can help you. Okay here we go!&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Nginx
&lt;/h2&gt;

&lt;p&gt;Pretty straightforward. Just run the command below if Nginx is not installed on your server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you should be able to access your server via http, just navigate to&lt;/p&gt;

&lt;p&gt;&lt;code&gt;http://yourserverip&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And you'll be presented Nginx's default welcome page. If not, you please check if your ports are not blocked and nginx is installed correctly. You can follow the &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-20-04"&gt;amazing tutorial by DigitalOcean&lt;/a&gt; to configure ports for nginx.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I'm not affiliated with DO in any manners, I just like their tutorials.&lt;/p&gt;

&lt;p&gt;Once you got Nginx working proceed to the next step:&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Nginx to serve your React app
&lt;/h2&gt;

&lt;p&gt;Now, for more detailed explanation you can follow &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-deploy-a-react-application-with-nginx-on-ubuntu-20-04"&gt;this tutorial on DigitalOcean&lt;/a&gt;. But I'll be demonstrating how you can configure it here too.&lt;/p&gt;

&lt;p&gt;To keep it simple and fast, I won't be demonstrating the server blocks but in production you should use them! For now, I'm just going to use the default one.&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;/etc/nginx/sites-enabled/default&lt;/code&gt; with your favorite editor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/nginx/sites-enabled/default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you scroll down, you'll see this specific line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root /var/www/html&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay this line means that Nginx will serve the files it found in that specific directory. So we'll move our built files there. If you want, you can change the directory I won't be changing it for this tutorial. Moving on!&lt;/p&gt;

&lt;h2&gt;
  
  
  Building our React app
&lt;/h2&gt;

&lt;p&gt;I'll be using the &lt;a href="https://github.com/gokayokyay/stewardx-docs"&gt;documentation repository of StewardX&lt;/a&gt; for demonstration purposes. It's a React app too 😊&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git clone https://github.com/gokayokyay/stewardx-docs
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;stewardx-docs
&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="c"&gt;# or yarn&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay now I can build my app&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm run build &lt;span class="c"&gt;# or yarn build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll see a &lt;code&gt;build&lt;/code&gt; folder has been created. Great!&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing and Running StewardX
&lt;/h2&gt;

&lt;p&gt;Head over to &lt;a href="https://github.com/gokayokyay/stewardx/releases/latest"&gt;releases page of StewardX&lt;/a&gt; and download the latest binary, it'll have a name like: &lt;code&gt;stewardx_${version}_${os}_${arch}&lt;/code&gt;. At the time of writing, the latest binary is named: &lt;code&gt;stewardx_v0.1.2_linux_x64&lt;/code&gt;. I suggest that you download it to a directory. I'll be creating a new one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;stewardx
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;stewardx
&lt;span class="nv"&gt;$ &lt;/span&gt;wget https://github.com/gokayokyay/stewardx/releases/download/v0.1.2/stewardx_v0.1.2_linux_x64 &lt;span class="nt"&gt;-O&lt;/span&gt; stewardx
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x stewardx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since it's not even in beta, you might have to build it from source, to do it please follow this link: &lt;a href="https://stewardx.dev/getting-started#building-it-from-source"&gt;Building it from source&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, you'll need to have a PostgreSQL instance running to start StewardX. You can get a free one or start your own by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-P&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 127.0.0.1:5432:5432 &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/postgres-data:/var/lib/postgresql/data"&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"1234"&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; pg postgres:alpine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; DON'T USE THIS COMMAND FOR PRODUCTION, PLEASE! IT'S PASSWORD IS 1234 😭&lt;/p&gt;

&lt;p&gt;You'll need your database URL. If you run the command above, then it is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;postgresql://postgres:1234@localhost:5432/postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now run this command while you're still at the same directory with &lt;code&gt;stewardx&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;STEWARDX_DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postgresql://postgres:1234@localhost:5432/postgres ./stewardx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see no output, then it means it's working! 😊&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the build script
&lt;/h2&gt;

&lt;p&gt;I'll create a new a directory for the script&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;ci-scripts
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;ci-scripts
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;react-ci.sh
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x react-ci.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now open the script with your favorite editor and paste the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nv"&gt;PROJECT_DIR_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;stewardx-docs
&lt;span class="nv"&gt;PROJECT_GIT_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://github.com/gokayokyay/stewardx-docs
&lt;span class="nv"&gt;PROJECT_PARENT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/
&lt;span class="nv"&gt;DEPLOY_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/www/html/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've just defined the variables here, moving on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;...
&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$PROJECT_PARENT&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PROJECT_PARENT&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;$PROJECT_DIR_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; 
&lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Directory &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_DIR_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; exists. Skipping git clone..."&lt;/span&gt; 
    &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$PROJECT_DIR_NAME&lt;/span&gt;
    git stash
    git pull
&lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Directory &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROJECT_DIR_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; doesn't exists, cloning it..."&lt;/span&gt;
    git clone &lt;span class="nv"&gt;$PROJECT_GIT_URL&lt;/span&gt;
    &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$PROJECT_DIR_NAME&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We pull the latest changes if available. Time to build it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;...
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Cleaning node_modules for a fresh start!"&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; node_modules
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Installing the modules..."&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Documentation repository don't have any tests, so I'm skipping test command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;...
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Now building it, this can take a while"&lt;/span&gt;
npm run build
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Cleaning old files in serve directory"&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="nv"&gt;$DEPLOY_DIR&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Okay, now moving the artifacts into the serve directory."&lt;/span&gt;
&lt;span class="nb"&gt;mv &lt;/span&gt;build/&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;$DEPLOY_DIR&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Done."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And save it.&lt;/p&gt;

&lt;p&gt;Issue this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and save it's output for the next step.&lt;/p&gt;

&lt;p&gt;Now to test our script, just run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./react-ci.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go check your website &lt;code&gt;http://yourserverip&lt;/code&gt; if it works, now it's time to&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a webhook
&lt;/h2&gt;

&lt;p&gt;Get the output of &lt;code&gt;pwd&lt;/code&gt; command from previous step. To add a webhook to StewardX we can either use it's &lt;a href="https://stewardx.dev/panel"&gt;panel&lt;/a&gt; (needs to be built) or just send a request to it by any web client, I'll be using curl:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{"task_name": "React app CI", "frequency": "Hook", "task_type": "CmdTask", "task_props": {"command":"/bin/bash #pwd_output#"}}'&lt;/span&gt; http://localhost:3000/tasks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change &lt;strong&gt;#pwd_output#&lt;/strong&gt; with the output you saved from previous step mine was: &lt;code&gt;/root/ci-scripts/react-ci.sh&lt;/code&gt; (yup used root, I like danger)&lt;/p&gt;

&lt;p&gt;This command will output an id, save it for the last step:&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the webhook from GitHub
&lt;/h2&gt;

&lt;p&gt;Now, it is time to add the webhook to the GitHub. Navigate to your project's repository, and click settings.&lt;/p&gt;

&lt;p&gt;Navigate to &lt;code&gt;Webhooks&lt;/code&gt; section from the left panel. Click &lt;code&gt;Add webhook&lt;/code&gt; button found on the top of the page. When the page opens up, you'll want to fill the &lt;code&gt;Payload URL&lt;/code&gt; with &lt;code&gt;yourserversurl:STEWARDX_PORT/execute/id_of_your_task&lt;/code&gt;, so it'll look something like &lt;code&gt;http://mydomain.com:3000/execute/c99ff533-d3c2-4ee3-9b8f-a972a9db00db&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And congratulations! You've created your own CI!&lt;/p&gt;

&lt;p&gt;For more information and documentation of StewardX, please visit &lt;a href="https://stewardx.dev"&gt;https://stewardx.dev&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I really appreciate if you leave a feedback 😊 Stay safe!&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>devops</category>
      <category>react</category>
      <category>nginx</category>
    </item>
    <item>
      <title>Introducing StewardX - Your automation buddy!</title>
      <dc:creator>Gökay Okyay</dc:creator>
      <pubDate>Wed, 05 May 2021 22:45:18 +0000</pubDate>
      <link>https://dev.to/gokayokyay/introducing-stewardx-your-automation-buddy-4g2e</link>
      <guid>https://dev.to/gokayokyay/introducing-stewardx-your-automation-buddy-4g2e</guid>
      <description>&lt;p&gt;Hey everyone! Long time no see.&lt;/p&gt;

&lt;h2&gt;
  
  
  A little history
&lt;/h2&gt;

&lt;p&gt;I was not active for couple of months but it was for a good cause. I've been learning Rust, and honestly, I fell in love with it! It's kinda low level but still gives one of the highest developer experiences while writing it.&lt;/p&gt;

&lt;p&gt;Several months ago I've decided to create a useful side project - a dynamic price checker that supports multiple websites. But it didn't happen because I couldn't find the right tools I needed. That's why I've build &lt;strong&gt;StewardX!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;h3&gt;
  
  
  So what is &lt;a href="https://stewardx.dev"&gt;StewardX&lt;/a&gt;?
&lt;/h3&gt;

&lt;p&gt;StewardX is actually an acronym! It stands for &lt;strong&gt;S&lt;/strong&gt;cheduled &lt;strong&gt;T&lt;/strong&gt;ask &lt;strong&gt;E&lt;/strong&gt;xecutor &lt;strong&gt;W&lt;/strong&gt;ith &lt;strong&gt;A&lt;/strong&gt;synchronous &lt;strong&gt;R&lt;/strong&gt;untime and &lt;strong&gt;D&lt;/strong&gt;atabase and an &lt;strong&gt;X&lt;/strong&gt; on the end. It is a scheduled task executor. Think of cron but with a database. Being written in Rust, gives us a compiled, lightweight single file executable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;It stores the outputs of tasks&lt;/li&gt;
&lt;li&gt;It can run tasks &lt;strong&gt;periodically&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;It can be &lt;strong&gt;triggered&lt;/strong&gt; to run tasks&lt;/li&gt;
&lt;li&gt;It supports both &lt;strong&gt;Dockerfile&lt;/strong&gt; and &lt;strong&gt;Docker image (prebuilt)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;It supports &lt;strong&gt;command tasks&lt;/strong&gt; (like echo "Hey")&lt;/li&gt;
&lt;li&gt;It serializes and saves tasks in &lt;strong&gt;Database&lt;/strong&gt; (Currently only PostgreSQL).&lt;/li&gt;
&lt;li&gt;Got a buggy and cute control panel 😛&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd like to point out the last item, it stores tasks in database! Means that, it's portable 😁&lt;/p&gt;

&lt;h3&gt;
  
  
  Task types
&lt;/h3&gt;

&lt;p&gt;StewardX currently supports two task &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker - As I said, it supports both dockerfiles and docker images&lt;/li&gt;
&lt;li&gt;Command&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But it can be easily extended, thanks to Rust's trait system. In fact, I'll be writing tutorials to explain how to add a new task type.&lt;/p&gt;

&lt;h3&gt;
  
  
  Frequency
&lt;/h3&gt;

&lt;p&gt;Currently, there are two frequency types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hook - &lt;em&gt;which is basically a webhook&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Cron - with seconds support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'll be writing more tutorials and guides about StewardX, but in the mean time, feel free to checkout the &lt;a href="https://github.com/gokayokyay/stewardx"&gt;repository&lt;/a&gt; and the &lt;a href="https://stewardx.dev"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;See you!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>devops</category>
      <category>rust</category>
      <category>showdev</category>
    </item>
    <item>
      <title>How to use Popper with Svelte, in a Sveltish way, with Actions!</title>
      <dc:creator>Gökay Okyay</dc:creator>
      <pubDate>Tue, 10 Nov 2020 18:15:05 +0000</pubDate>
      <link>https://dev.to/gokayokyay/how-to-use-popper-with-svelte-in-a-sveltish-way-with-actions-2h02</link>
      <guid>https://dev.to/gokayokyay/how-to-use-popper-with-svelte-in-a-sveltish-way-with-actions-2h02</guid>
      <description>&lt;h1&gt;
  
  
  What is Popper?
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://popper.js.org/" rel="noopener noreferrer"&gt;Popper&lt;/a&gt; identifies itself as a &lt;code&gt;TOOLTIP &amp;amp; POPOVER POSITIONING ENGINE&lt;/code&gt;. It basically helps your popovers and tooltips position properly. Popper is awesome and used by millions and giants (according to their website) such as Microsoft, Atlassian, GitLab, etc. And I use it at work and while working on my side projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Okay, but with Svelte we can use any tools or libraries without an extra work or binding
&lt;/h2&gt;

&lt;p&gt;Yes but it doesn't mean that we can't improve our codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Yep, you're right, so how to use it?
&lt;/h2&gt;

&lt;p&gt;First, I want to show you how you can use it without &lt;code&gt;Sveltish&lt;/code&gt; way. Let's create a new Svelte project with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx degit sveltejs/template my-svelte-project
&lt;span class="nb"&gt;cd &lt;/span&gt;sveltishpopper
npm i
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then install Popper&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i @popperjs/core
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open &lt;code&gt;src/App.svelte&lt;/code&gt; with your favorite editor, and delete everything.&lt;/p&gt;

&lt;p&gt;Create a file named &lt;code&gt;Modal.svelte&lt;/code&gt;, then paste following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;modal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;justify&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;align&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="nx"&gt;vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="nx"&gt;vw&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;flex&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;background&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;wheat&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;border&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;modal&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;margin&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="nx"&gt;em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/style&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;modal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;Hello&lt;/span&gt; &lt;span class="nx"&gt;Popper&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://popper.js.org/static/popper-logo-394b4ea5914aad7fc580f418ed0cfb17.svg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Popper logo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's just a basic modal with a background color.&lt;/p&gt;

&lt;p&gt;Now open &lt;code&gt;App.svelte&lt;/code&gt; and paste&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;onMount&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createPopper&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@popperjs/core/dist/esm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Modal&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Modal.svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;popButton&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isModalActive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toggleModal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;isModalActive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isModalActive&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nf"&gt;onMount&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;createPopper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;popButton&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;popButton&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nl"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;toggleModal&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;Pop&lt;/span&gt; &lt;span class="nx"&gt;it&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;isModalActive&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Modal&lt;/span&gt; &lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sr"&gt;/if&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, nothing really challenging goes on&lt;br&gt;
And congratz! You got yourself a functioning modal with awesome positioning.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fb4f0rsfx1dg11h5fn2uf.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fb4f0rsfx1dg11h5fn2uf.gif" alt="bad popper"&gt;&lt;/a&gt;&lt;br&gt;
This implementation is really simple but everytime you want to use a modal with popper, you need to repeat this implementation. How can we improve?&lt;/p&gt;
&lt;h2&gt;
  
  
  Action!
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia1.tenor.com%2Fimages%2Ff9eae32ae9741644afccb8c1aa68b06b%2Ftenor.gif%3Fitemid%3D16202503" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia1.tenor.com%2Fimages%2Ff9eae32ae9741644afccb8c1aa68b06b%2Ftenor.gif%3Fitemid%3D16202503" alt="Action gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now create a file named, actually it doesn't really matter because this isn't really a project but let's call it, &lt;code&gt;PopperAction.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And paste following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createPopper&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@popperjs/core/dist/esm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;popover&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;popperInstance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;componentInstance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;renderedComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isActive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;modal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toggle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopPropagation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;isActive&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;hide&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;detectClickOutside&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;renderedComponent&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;renderedComponent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;hide&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;show&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;componentInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;props&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;isActive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;renderedComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`#&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;popperInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createPopper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;renderedComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;modifiers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;offset&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;detectClickOutside&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hide&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;renderedComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`#&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;isActive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;popperInstance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;popperInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nx"&gt;popperInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;componentInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$destroy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;detectClickOutside&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;detectClickOutside&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Okay, what the heck??
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia1.tenor.com%2Fimages%2Fa4ccb1ae7720c8bdac17ecd78fe3ed43%2Ftenor.gif%3Fitemid%3D13712192" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia1.tenor.com%2Fimages%2Fa4ccb1ae7720c8bdac17ecd78fe3ed43%2Ftenor.gif%3Fitemid%3D13712192" alt="what the ..."&gt;&lt;/a&gt;&lt;br&gt;
This implementation is more confusing but let me explain what's happening down there. (You can skip if you understood what it does.)&lt;/p&gt;

&lt;p&gt;So, we are defining a function that takes, a node and some props. We add a click event listener to the node (in this case its a button) and we bind it to a toggle function, which toggles the modal (eh?).&lt;/p&gt;

&lt;p&gt;Show function is creating a popper instance every time we click to the button, and hide is hiding the modal and destroying the popper instance. You can figure out the optimizations yourselves, I'm in a rush!&lt;/p&gt;

&lt;p&gt;As a bonus I ended up adding a click outside handler which detects clicks that are outside of the modal.&lt;/p&gt;

&lt;p&gt;We return an object from the action.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;detectClickOutside&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It has a special method named &lt;code&gt;destroy&lt;/code&gt;, it's duty is to clean up effects ( :) ).&lt;/p&gt;

&lt;h2&gt;
  
  
  Hmm, seems legit, but how to use it?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.tenor.com%2Fimages%2F743666c385590f747a6e5596f73d3b6c%2Ftenor.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.tenor.com%2Fimages%2F743666c385590f747a6e5596f73d3b6c%2Ftenor.gif" alt="seems legit"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's the awesome part. Get ready to shocked in 3, 2, 1...&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flnt8n31erguycgnncoto.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flnt8n31erguycgnncoto.png" alt="Carbon last"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;popover&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./PopperAction.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Modal&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Modal.svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;popover&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Modal&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;Pop&lt;/span&gt; &lt;span class="nx"&gt;it&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look how beautiful it is. 😢&lt;/p&gt;

&lt;p&gt;Okay this is it. Have a nice day.&lt;/p&gt;

&lt;p&gt;&lt;sup&gt;PS, checkout official &lt;a href="https://github.com/popperjs/svelte-popper" rel="noopener noreferrer"&gt;svelte package of popper&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Managing VSCode Profiles for the Polyglot Developers</title>
      <dc:creator>Gökay Okyay</dc:creator>
      <pubDate>Sun, 07 Jun 2020 11:06:58 +0000</pubDate>
      <link>https://dev.to/gokayokyay/managing-vscode-profiles-for-the-polyglot-developers-5d1j</link>
      <guid>https://dev.to/gokayokyay/managing-vscode-profiles-for-the-polyglot-developers-5d1j</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fev1gvv6xlsy3eypvyqzx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fev1gvv6xlsy3eypvyqzx.png" alt="Programming languages meme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Image credit: &lt;a href="https://programmerhumour.tumblr.com/post/187131622245/javascript-mocking-joke-645342" rel="noopener noreferrer"&gt;https://programmerhumour.tumblr.com/post/187131622245/javascript-mocking-joke-645342&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you use multiple programming languages in your daily life, you probably need numerous extensions which target specific programming languages.&lt;/p&gt;

&lt;p&gt;I use Go, Node.js, Python (sometimes), Rust and since one month, Deno. I need ESLint for Node, Go Extension for Golang, RLS for Rust and so on.&lt;/p&gt;

&lt;p&gt;My laptop is 10 years old and it's getting slower every day so as my vscode profile. It is bloated with extensions. Think of getting minimum 3 extensions for every language you write! So what's the solution? If you don't like to hack stuff like I do, search for an extension that can help with this issue (look at the irony here). But if you're like me, the solution is &lt;strong&gt;VSCode Profiles!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note:&lt;/em&gt;&lt;/strong&gt; Some steps are taken from &lt;a href="https://dev.to/jsjoeio/how-to-create-code-profiles-in-vscode-3ofo"&gt;https://dev.to/jsjoeio/how-to-create-code-profiles-in-vscode-3ofo&lt;/a&gt; - Check out this amazing post too!&lt;/p&gt;

&lt;h2&gt;
  
  
  First, create the root of profiles directory by pasting following line to your terminal
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;mkdir &lt;/span&gt;code-profiles &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;code-profiles
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You've probably know what the above line does but here's the explanation for those who don't: It navigates to your home directory (of your current terminal user) and creates a directory then it navigates into it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Second, prepare the profile directory for the language you'll work with
&lt;/h2&gt;

&lt;p&gt;It can be anything, I can't force you to work with a specific language or a tool 😄, but as an example I'll go with Deno.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;deno
&lt;span class="nb"&gt;cd &lt;/span&gt;deno
&lt;span class="nb"&gt;mkdir &lt;/span&gt;data extensions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  (Optional) Copy your settings file
&lt;/h2&gt;

&lt;p&gt;If you want to keep your current settings, open &lt;code&gt;settings.json&lt;/code&gt; in VSCode and copy your settings. Then while in the &lt;code&gt;deno&lt;/code&gt; directory we've just created:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;data
&lt;span class="nb"&gt;mkdir &lt;/span&gt;User
nano settings.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And paste the content of &lt;code&gt;settings.json&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making our lives easier, adding an alias!
&lt;/h2&gt;

&lt;p&gt;Actually this step is optional too but I strongly recomment it or you'll have to write two paths and two flags each time you want to open your profile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;
&lt;span class="c"&gt;# I'll open my bashrc file because I'm using linux with bash but other shells are similar too&lt;/span&gt;
nano .bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And at the end of the file add this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;alias &lt;/span&gt;code-deno&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"code --user-data-dir ~/code-profiles/deno/data/ --extensions-dir ~/code-profiles/deno/extensions/"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save and close it.&lt;/p&gt;

&lt;p&gt;Then restart your terminal or source your bashrc file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source&lt;/span&gt; .bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Voila!
&lt;/h2&gt;



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

&lt;/div&gt;



&lt;p&gt;You now have a vscode profile for Deno with extensions specific to it! When you want to code with another PL just repeat the same steps for that language, and you'll have a fresh VSCode without bloated with extensions!&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://dev.to/jsjoeio/how-to-create-code-profiles-in-vscode-3ofo"&gt;How to Create Code Profiles in VSCode &lt;/a&gt;&lt;br&gt;
&lt;a href="https://code.visualstudio.com/docs/editor/extension-gallery#_command-line-extension-management" rel="noopener noreferrer"&gt;Managing Extensions in Visual Studio Code&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>tutorial</category>
      <category>productivity</category>
      <category>tips</category>
    </item>
    <item>
      <title>RemoteCareer 🦁 - Job board that helps nature and animals </title>
      <dc:creator>Gökay Okyay</dc:creator>
      <pubDate>Fri, 24 Jan 2020 21:37:05 +0000</pubDate>
      <link>https://dev.to/gokayokyay/remotecareer-job-board-that-helps-nature-and-animals-360e</link>
      <guid>https://dev.to/gokayokyay/remotecareer-job-board-that-helps-nature-and-animals-360e</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6Z93QSMS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/yfwcrke404sdxgy9huiv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6Z93QSMS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/yfwcrke404sdxgy9huiv.png" alt="RemoteCareer logo"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://remotecareer.org"&gt;Remote Career&lt;/a&gt;&lt;br&gt;
Client repo: &lt;a href="https://github.com/gokayokyay/remote-career-client"&gt;Remote-Career-Client&lt;/a&gt;&lt;br&gt;
Server repo: &lt;a href="https://github.com/gokayokyay/remote-career-server"&gt;Remote-Career-Server&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  How does it help nature and animals?
&lt;/h4&gt;

&lt;p&gt;Well, since this is the beginning, it doesn't. But the main idea of this app is to donate 90% of every sale to &lt;b&gt;WORLDWIDE&lt;/b&gt; animal charities. 10% is for the future DB/server/domain costs.&lt;/p&gt;

&lt;h4&gt;
  
  
  Story of the app
&lt;/h4&gt;

&lt;p&gt;As a new grad I was looking for remote jobs, came across few job boards then something got my attention. The price to post a job was in three digits! It seemed too high for me then I thought - like every jealous developer - "I can create this web app too.". But it's a side project for me so I want it to be useful for everyone.&lt;/p&gt;

&lt;p&gt;I've learned React three years ago, so it was an opportunity to refresh my knowledge and learn new tools (like Next.js). For the backend I went &lt;a href="https://github.com/the-benchmarker/web-frameworks"&gt;to this repo&lt;/a&gt; and picked a Node framework, and it was something called Restana but somehow it lost its rank now. But it's the framework I chose, it's somehow an Express.js alternative.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Stack
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hFJM27Ls--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/966/1%2A8g-FaXXbEUFP11oZD1kfaA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hFJM27Ls--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/966/1%2A8g-FaXXbEUFP11oZD1kfaA.jpeg" alt="Next, React, Node"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;credits to: &lt;a href="https://engineering.cimri.com/a-simple-next-js-project-structure-1c8e90088209"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h5&gt;
  
  
  Frontend
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;React&lt;/li&gt;
&lt;li&gt;Next.js&lt;/li&gt;
&lt;li&gt;Material-ui&lt;/li&gt;
&lt;li&gt;Redux&lt;/li&gt;
&lt;li&gt;Zeit's Now for deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Backend
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Restana&lt;/li&gt;
&lt;li&gt;Redis - for ip blocking&lt;/li&gt;
&lt;li&gt;Nodemailer with Mailgun&lt;/li&gt;
&lt;li&gt;MongoDB&lt;/li&gt;
&lt;li&gt;Mongoose&lt;/li&gt;
&lt;li&gt;IBM Cloud Storage as file service&lt;/li&gt;
&lt;li&gt;Pino for logging&lt;/li&gt;
&lt;li&gt;Heroku for deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Process of developing
&lt;/h4&gt;

&lt;p&gt;So I thought there will be three main pages of the app, Home page where posted jobs are shown, Job Page where people can read the description and requirements, and finally Post a Job page where companies can post their job openings.&lt;/p&gt;

&lt;p&gt;Then I designed these pages with &lt;a href="https://www.figma.com/"&gt;Figma&lt;/a&gt;. I wanted a very simple design, because I'm not a designer.&lt;/p&gt;

&lt;h5&gt;
  
  
  Homepage
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1uBZbXAA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/3hi3w444bwd3ax3lg5if.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1uBZbXAA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/3hi3w444bwd3ax3lg5if.png" alt="Home page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I wanted a hero component, a navigation bar and job listing section for the home page.&lt;/p&gt;

&lt;h5&gt;
  
  
  Post a job
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yne220R2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/np7j9bop4dwiqw84uerr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yne220R2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/np7j9bop4dwiqw84uerr.png" alt="Post a job page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the posting page I wanted it to be reactive, I want the job card to be updated as you change fields.&lt;/p&gt;

&lt;h5&gt;
  
  
  Job
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UHCUuLhV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/4estwdok0rscpn8g6tx5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UHCUuLhV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/4estwdok0rscpn8g6tx5.png" alt="Job page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This page needed to be simple and template-like.&lt;/p&gt;

&lt;h5&gt;
  
  
  Other pages
&lt;/h5&gt;

&lt;p&gt;When these pages were finished, I needed some other pages like Editing page, Admin page etc...&lt;/p&gt;

&lt;p&gt;But for the MVP I omitted Admin page functionalities.&lt;/p&gt;

&lt;h4&gt;
  
  
  Thoughts about tools
&lt;/h4&gt;

&lt;h5&gt;
  
  
  Next.js
&lt;/h5&gt;

&lt;p&gt;Very useful tool. Improves performance a lot and SSR by default. But in my opinions, ecosystem can be improved. Adding material-ui was a total pain so I started with official example.&lt;/p&gt;

&lt;h5&gt;
  
  
  Now by Zeit
&lt;/h5&gt;

&lt;p&gt;Another very useful tool by Zeit. It's amazing. Deploys automatically with every commit to master branch. The only con of this tool is DNS settings. It should be able to be configurable within the web app, not only from the cli.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final words
&lt;/h3&gt;

&lt;p&gt;I want this app to be ours, people who want to help animals/nature. So that I made this app open source available &lt;a href="https://github.com/gokayokyay/remote-career-server"&gt;here&lt;/a&gt; and &lt;a href="https://github.com/gokayokyay/remote-career-client"&gt;here&lt;/a&gt;. Feel free to contribute 💚💚.&lt;/p&gt;

&lt;p&gt;It would be awesome if hiring companies post their job offer at this website, and it's free until I found someone to be funding manager of the project 😋.&lt;/p&gt;

&lt;p&gt;Btw, don't forget to checkout the first job offer &lt;a href="https://remotecareer.org/jobs/5e28de8e9e47550004c5690e"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Feel free to contact with email: &lt;a href="//mailto:gokayokyay@hotmail.com"&gt;gokayokyay@hotmail.com&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>5 Minutes Tutorial Series - NodeJS upload files to Minio</title>
      <dc:creator>Gökay Okyay</dc:creator>
      <pubDate>Wed, 01 Jan 2020 18:52:27 +0000</pubDate>
      <link>https://dev.to/gokayokyay/5-minutes-tutorial-series-nodejs-upload-files-to-minio-3dj0</link>
      <guid>https://dev.to/gokayokyay/5-minutes-tutorial-series-nodejs-upload-files-to-minio-3dj0</guid>
      <description>&lt;p&gt;Hello everyone, I am starting a new series called "5 Minutes Tutorial Series". In this tutorial, I'll show how can you upload a file to a Node server and then upload it to Minio Object Storage. Since it is about Minio, I'm assuming that you know what it is, but if you don't click &lt;a href="https://min.io/"&gt;here&lt;/a&gt; to learn more.&lt;/p&gt;

&lt;p&gt;We'll be using &lt;a href="https://www.fastify.io/"&gt;fastify&lt;/a&gt; as our server framework. If you're using express, you can find an awesome post by &lt;a href="https://www.thepolyglotdeveloper.com/2017/03/upload-files-minio-object-storage-cloud-node-js-multer/"&gt;thepolygotdeveloper&lt;/a&gt; here. Let's begin!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# create new project&lt;/span&gt;
&lt;span class="nb"&gt;mkdir &lt;/span&gt;fastify-minio
&lt;span class="nb"&gt;cd &lt;/span&gt;fastify-minio

&lt;span class="c"&gt;# initialize npm project&lt;/span&gt;
npm init &lt;span class="nt"&gt;-y&lt;/span&gt;

&lt;span class="c"&gt;# install fastify, fastify-file-upload, minio&lt;/span&gt;
npm i fastify fastify-file-upload minio
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a file named index.js then add following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fastify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fastify&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fastify&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fastify-file-upload&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/upload&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;App is listening on port 3000!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we have a very basic fastify server. Next create a file named minioClient.js with the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Minio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;minio&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;minioClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Minio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;endPoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;play.minio.io&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;9000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;secure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;accessKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Q3AM3UQ867SPQQA43P2F&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;secretKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;minioClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're using minio's playground but feel free to change the configuration as you wish. Next we'll modify our index.js code to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fastify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fastify&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fastify&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// -&amp;gt;CHANGED&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;minioClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./minioClient&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// CHANGED&amp;lt;-&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fastify-file-upload&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/upload&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// -&amp;gt;CHANGED&lt;/span&gt;
    &lt;span class="nx"&gt;minioClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;putObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;etag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://play.minio.io:9000/test/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="c1"&gt;// CHANGED&amp;lt;-&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;App is listening on port 3000!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see what's changed by looking at //CHANGED code blocks. But I want you to focus on minioClient part. We put object to a bucket named "test" with filename and data buffer. By the way notice the files.image part, in this case the file's key is "image". And the file's url is MINIO_ENDPOINT:MINIO_PORT/BUCKET_NAME/FILE_NAME. Since minio uses a technique called "presigned url" the file won't be accessible from that url. But we can change it by changing bucket policy. Here's the policy I use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="nl"&gt;"AWS"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetBucketLocation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="s2"&gt;"s3:ListBucket"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::bucket"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="nl"&gt;"AWS"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::bucket/*"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you apply this policy via "setBucketPolicy" method of client, the files in the bucket will be accessible publicly and the url will be available permanently. You can see the method's docs &lt;a href="https://docs.min.io/docs/javascript-client-api-reference.html#setBucketPolicy"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Last thing, it can be problematic to use files' original names. I suggest trying some package like &lt;a href="https://www.npmjs.com/package/uuid"&gt;uuid&lt;/a&gt; to prevent it.&lt;/p&gt;

&lt;p&gt;Okay it's been 5 minutes already, see you in another tutorial!&lt;/p&gt;

</description>
      <category>node</category>
      <category>minio</category>
      <category>javascript</category>
      <category>api</category>
    </item>
    <item>
      <title>API Authentication Workflow with JWT and Refresh Tokens</title>
      <dc:creator>Gökay Okyay</dc:creator>
      <pubDate>Tue, 03 Dec 2019 21:10:16 +0000</pubDate>
      <link>https://dev.to/gokayokyay/api-authentication-workflow-with-jwt-and-refresh-tokens-5312</link>
      <guid>https://dev.to/gokayokyay/api-authentication-workflow-with-jwt-and-refresh-tokens-5312</guid>
      <description>&lt;p&gt;Hey everyone, this is my first post so go easy on me :P&lt;/p&gt;

&lt;p&gt;So I want this post to help anyone who wants to build an authentication system. I'm sharing a workflow, not the implementation, so that you can change the implementation in the way of your needs.&lt;/p&gt;

&lt;p&gt;I'll add some scenarios throughout the post and will move on to server-side and lastly client-side. I'll assume that you already have a registration system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scenario Part 1
&lt;/h2&gt;

&lt;p&gt;User registered. Okay, then we need to send a jwt and a refresh token. So server creates it and sends them back to the user, user's browser saves tokens then our cute little user is free to roam around in our app. So what happened actually?&lt;/p&gt;

&lt;h2&gt;
  
  
  Server-Side
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Client registered&lt;/li&gt;
&lt;li&gt;Created a short-lived JWT and a refresh token for the specified user&lt;/li&gt;
&lt;li&gt;Save the refresh token in a DB, it can be a Key-Value DB like Redis.&lt;/li&gt;
&lt;li&gt;Send JWT back to client, and add the refresh token to client's Cookie Storage with HttpOnly and Secure flags.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can set cookie in node like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Set-Cookie&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo=bar; HttpOnly&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Client-Side
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Hit server's registration endpoint.&lt;/li&gt;
&lt;li&gt;Save JWT to localStorage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a note: Local storage is vulnerable to XSS attacks so becareful :)&lt;/p&gt;

&lt;p&gt;Okay that wasn't that much. But a couple of questions can be arised with our little note. Here's the most specific one: Why did we save JWT to localStorage if it is vulnerable?&lt;/p&gt;

&lt;h4&gt;
  
  
  The Answer
&lt;/h4&gt;

&lt;p&gt;We have saved JWT to client's local storage because you might have noticed, our JWT is short-lived, say 30 minutes. This way we can add JWT to Authorization header of our API requests. (The bearer thingy)&lt;/p&gt;

&lt;p&gt;And then we have created another token called refresh token, this can anything, your pet's name reversed with a counter or some random numbers... anything! I prefer a node package called "uuid". We saved the refresh token to client's cookie storage with httponly and secure flags. This means that this particular cookie won't be accessible by javascript. And the secure flag is about https, you can understand what it does :P&lt;/p&gt;

&lt;p&gt;This way when user hits our API, our server can validate the JWT and refresh token of the user.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scenario Part 2
&lt;/h2&gt;

&lt;p&gt;User never gets bored in our app! He constantly refreshes the feed and wait for new things, but guess what our little user? 30 minutes have passed already! So your JWT is &lt;strong&gt;EXPIRED&lt;/strong&gt;. Now what?&lt;/p&gt;

&lt;p&gt;This time I'll explain it like a sequence diagram.&lt;/p&gt;

&lt;h2&gt;
  
  
  Client-Side
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;User makes an API request with expired JWT.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Server-side
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;API request is received, check the JWT and refresh token. &lt;strong&gt;BOOM&lt;/strong&gt; JWT is expired, send unauthorized response to client (401).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Client-Side
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Received unauthorized response from the previous API request.&lt;/li&gt;
&lt;li&gt;Hit refresh endpoint of the API.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Server-side
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Received the expired JWT checked it and refresh token is assigned to current user. Now refresh the JWT and send it back to user.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Client-side
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Received JWT, saved it to the localStorage again.&lt;/li&gt;
&lt;li&gt;Repeat the failed API request.&lt;/li&gt;
&lt;li&gt;Continue to operate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In node's jsonwebtoken package, there's an option while verifying the jwt. It is &lt;em&gt;ignoreExpiration&lt;/em&gt;. You can check if the token is modified.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scenario Part 3
&lt;/h2&gt;

&lt;p&gt;So our user is sleepy, he wants to logout. But it's not that he got bored, he just wants to sleep :). He clicked the logout button. What happens now?&lt;/p&gt;

&lt;h2&gt;
  
  
  Client-Side
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Clear the localStorage or just remove the jwt.&lt;/li&gt;
&lt;li&gt;Make an API logout request.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Server-Side
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Received logout request. Delete refresh token from the DB (like redis :P)&lt;/li&gt;
&lt;li&gt;Set refresh token cookie's expiration date to any date in past.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Poof&lt;/strong&gt; our user is logged out.&lt;/p&gt;

&lt;p&gt;Such a long post for the first time eh? I might add more information if posts can be edited :P.&lt;/p&gt;

&lt;p&gt;Important note: Mobile authentication should be different than this. I will share a post about it in future.&lt;/p&gt;

&lt;p&gt;See you in another post!&lt;/p&gt;

</description>
      <category>jwt</category>
      <category>authentication</category>
      <category>token</category>
      <category>node</category>
    </item>
  </channel>
</rss>
