<?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: Abdus Azad</title>
    <description>The latest articles on DEV Community by Abdus Azad (@abdus).</description>
    <link>https://dev.to/abdus</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%2F67622%2F7906c791-8ded-4c8c-ab66-29d594a80a96.jpg</url>
      <title>DEV Community: Abdus Azad</title>
      <link>https://dev.to/abdus</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/abdus"/>
    <language>en</language>
    <item>
      <title>Build a Search API from Scratch</title>
      <dc:creator>Abdus Azad</dc:creator>
      <pubDate>Wed, 23 Feb 2022 07:23:08 +0000</pubDate>
      <link>https://dev.to/abdus/build-a-search-api-from-scratch-jaa</link>
      <guid>https://dev.to/abdus/build-a-search-api-from-scratch-jaa</guid>
      <description>&lt;p&gt;Search functionality is one of the most common features you see in any digital product. I would hesitate to use a product that does not contain a search bar (given that the search bar is necessary). However, creating a search engine as big as Google would take lots of time and energy, and may not be possible for a lone developer. So, here I will demonstrate a simple way to build a search engine for small to medium-sized products.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stack
&lt;/h2&gt;

&lt;p&gt;Before getting into the actual coding, let me introduce you to the tech stack. I will be using JavaScript for both front-end and back-end, and LunrJS to index and search through the text content.&lt;/p&gt;

&lt;p&gt;In case you have not heard of LunrJS, it is a full-text search library that is &lt;em&gt;a bit like Solr, but much smaller and not as bright&lt;/em&gt;. A library that is written in JavaScript for both client-side and server-side. LunrJS indexes text-based content into a JSON document. The production bundle of LunrJS 8.2 KB in size, which makes it a good fit on the front-end too.&lt;/p&gt;

&lt;p&gt;Some of the Lunr alternatives are: &lt;a href="https://github.com/bvaughn/js-search"&gt;js-search&lt;/a&gt;, &lt;a href="https://github.com/nextapps-de/flexsearch"&gt;flexsearch&lt;/a&gt;, &lt;a href="https://github.com/krisk/Fuse"&gt;fuse&lt;/a&gt;, &lt;a href="https://github.com/kbrsh/wade"&gt;wade&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flow
&lt;/h2&gt;

&lt;p&gt;To integrate search functionality into a website, we need some data. We will be searching for specific information from this data lake (well, quite a small lake for now). To store data, we can use any of the available databases depending on the project's needs. For this demonstration, I am using MongoDB (via Mongoose ORM).&lt;/p&gt;

&lt;p&gt;Here's how to initialize a database connection using Mongoose in a serveless environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mongoose&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;mongoDBConn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Connection&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;connectionStr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DATABASE_URI&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="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;connectionStr&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="s2"&gt;`string`&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="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`database uri: not a string`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;mongoDBConn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;mongoose&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;connectionStr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;m&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;mongoDBConn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&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;error&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 may notice an unusual way of initializing the database connection object. I am caching it inside a variable. This way, the subsequent serverless invocation will be able to reuse it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getBlogSchema&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;BlogCollection&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;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;required&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;unique&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="c1"&gt;// rest of the document fields&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;BlogCollection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&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;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Blog`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;BlogCollection&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;syncIndexes&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;model&lt;/span&gt;&lt;span class="p"&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;const&lt;/span&gt; &lt;span class="nx"&gt;blogModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Blog&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Blog&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;getBlogSchema&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, another non-conventional way of creating a database model, all thanks to serverless. Since we cached the database into a variable, we should check if the model exists in the cache. We can't recreate a model in Mongoose. Trying to do so will throw an error.&lt;/p&gt;

&lt;p&gt;Moving on, we have to install the package &lt;code&gt;lunr&lt;/code&gt; by running &lt;code&gt;yarn add lunr&lt;/code&gt;. Once done, it is time to setup &lt;code&gt;lunr&lt;/code&gt;. Let's start with the &lt;code&gt;import&lt;/code&gt;s.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fs&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;lunr&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lunr&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;blogModal&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="s2"&gt;./path/to/blogModel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, I am going to write a few helper functions. These functions will help us execute the search systematically.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;buildSearchIndex&lt;/code&gt;: As the name suggests, this function will build a search index. A search index is a collection of data stored in a disk or inside the memory. This collection is parsed and stored in a way so that querying it becomes easier and more efficient.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;buildSearchIndex&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;lunr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Index&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;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;docs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;blogModel&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lunr&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;builder&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;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`_id`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`title`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// additional fields if any&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
          &lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&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="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;err&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's understand what is going on. First, we are calling the &lt;code&gt;lunr&lt;/code&gt; function, which accepts a callback. The first parameter of the callback is an object called &lt;code&gt;builder&lt;/code&gt; (passed automatically by &lt;code&gt;lunr&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;builder.ref&lt;/code&gt; method is used to reference the original document. Assign a unique field to it. &lt;code&gt;_id&lt;/code&gt;, for example.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;builder.field&lt;/code&gt; method tells the &lt;code&gt;builder&lt;/code&gt; what field to index. Add all the fields you want to search in.&lt;/p&gt;

&lt;p&gt;Finally, we are adding documents to the index by calling &lt;code&gt;builder.add&lt;/code&gt; method inside a &lt;code&gt;for&lt;/code&gt; loop.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;saveSearchIndex&lt;/code&gt;: This function saves a given search index to the file system. When the data lake size increase, it is no longer efficient to create an index on every API call. In such cases, &lt;code&gt;lunr&lt;/code&gt; could load a pre-created index from the disk.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;saveSearchIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;lunr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;writeFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;INDEX_PATH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;utf-8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&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="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;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;loadSearchIndex&lt;/code&gt;: This function loads an index to the memory so that &lt;code&gt;lunr&lt;/code&gt; could perform operatons on it.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;loadSearchIndex&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;lunr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Index&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&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;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;INDEX_PATH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`utf-8`&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;lunr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&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="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;err&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;deleteSearchIndex&lt;/code&gt; and &lt;code&gt;hasSearchIndex&lt;/code&gt;: These functions are used to delete an existing search index from disk, and to check whether a given index exists.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;deleteSearchIndexFile&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;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unlinkSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;INDEX_PATH&lt;/span&gt;&lt;span class="p"&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="nx"&gt;hasSearchIndex&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;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;existsSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;INDEX_PATH&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;Now that we have all the helper functions ready, we could start implementing the feature. Inside the API endpoint file, we are going to initialize the &lt;code&gt;lunr&lt;/code&gt; index.&lt;/p&gt;

&lt;p&gt;A point worth noting, we have to update the index after a certain period. Otherwise, the index will not have all the data from the database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;searchIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;lunr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Index&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;indexBuiltAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&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;TEN_MIN_IN_MILI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;600000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code snippet, I declared a few variables. Variable &lt;code&gt;indexBuiltAt&lt;/code&gt; stores the most recent build timestamp. Based on this timestamp, I will be updating the index.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;createSearchIndex&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;buildSearchIndex&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;index&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;searchIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;saveSearchIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;indexBuiltAt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Date&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="k"&gt;catch&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above function creates a search index and stores them in the variables declared earlier.&lt;/p&gt;

&lt;p&gt;Finally, it's time to glue everything together and make it a working solution.&lt;/p&gt;

&lt;p&gt;Following code-block is pretty much explains itself. I used &lt;code&gt;setImmediate&lt;/code&gt; so that it does not block the main event loop.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;setImmediate&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hasSearchIndex&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;searchIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;loadSearchIndex&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;createSearchIndex&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;setInterval&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="c1"&gt;// reload search index at every 10 mins&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;indexBuiltAt&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
      &lt;span class="nx"&gt;indexBuiltAt&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;TEN_MIN_IN_MILI&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;getTime&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hasSearchIndex&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;searchIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;loadSearchIndex&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;createSearchIndex&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="mi"&gt;30&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&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;At this point, everything is done. And we are ready to run queries on this index. To run a query using &lt;code&gt;lunr&lt;/code&gt;, we have to call the &lt;code&gt;search&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ids&lt;/span&gt; &lt;span class="o"&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;searchIndex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search&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;search&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&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;join&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="s2"&gt;*`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isValidObjectId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ref&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;ids&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I am collecting all the matching &lt;code&gt;id&lt;/code&gt;s into an Array. Using these &lt;code&gt;id&lt;/code&gt;s, I will retrieve the actual documents, and send them as the API response.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This set-up is ideal if your product is relatively small (and do not have a huge amount of data to run the operations upon). I have used the same setup in &lt;a href="https://github.com/abdus/awesome-websites/"&gt;one of the projects I built&lt;/a&gt;.This can be improved a lot. For instance, you could build the search index every time there is a new entry in the database.&lt;/p&gt;

&lt;p&gt;For more information on &lt;code&gt;lunr&lt;/code&gt;, please check the &lt;a href="https://lunrjs.com/"&gt;official website&lt;/a&gt;. It has many other &lt;a href="https://lunrjs.com/docs/lunr.Query.html"&gt;useful things&lt;/a&gt; built-in.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>search</category>
      <category>node</category>
    </item>
    <item>
      <title>Why TypeScript</title>
      <dc:creator>Abdus Azad</dc:creator>
      <pubDate>Mon, 26 Jul 2021 15:09:12 +0000</pubDate>
      <link>https://dev.to/abdus/why-typescript-4e31</link>
      <guid>https://dev.to/abdus/why-typescript-4e31</guid>
      <description>&lt;p&gt;For many of the developers, TypeScript seems like a completely new language. But to me, it is just JavaScript with added type system. In this post, I am going to discuss why we should use TypeScript over plain old JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  Type System
&lt;/h2&gt;

&lt;p&gt;Let me lead the post with TypeScript’s awesome typing-system. In plain JavaScript, there are no types. Values are assigned to variables dynamically. When I say a language is dynamic, I essentially mean that we can re-assign variables with different data types. For example, if we a declare variable &lt;code&gt;let whatever = 10&lt;/code&gt;, this variable will be of type &lt;code&gt;Integer&lt;/code&gt;. Now in a strongly-typed static language, we cannot reassign this variable with a different data type, say a &lt;code&gt;String&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If a programmer has not used any statically-typed languages in the past, this additional type-system on top of JavaScript can be a bit hectic and frustrating while working on a project. But if we look at the bigger picture, we can prevent so many bugs right at the compile time by passing values of the correct type.&lt;/p&gt;

&lt;p&gt;For example, if a function parameter type is set as &lt;code&gt;String&lt;/code&gt;, and we pass a value of type &lt;code&gt;Number&lt;/code&gt; while invoking it, TypeScript compiler will not compile the code. On the other hand, JavaScript will report no error at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Self Documenting
&lt;/h2&gt;

&lt;p&gt;Since each variable in TypeScript has a type associated with it, it’s very easy to read and understand that codebase. Check out the below code for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;DbOpts&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;connectDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DbOpts&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;opts&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;In the above code snippet, if we call &lt;code&gt;connectDB()&lt;/code&gt; function without the correct parameter (or even a single property, as all of the properties, are&lt;code&gt;required&lt;/code&gt;), the TypeScript compiler will throw an error saying that there’s a type mismatch. Isn’t that useful?&lt;/p&gt;

&lt;p&gt;Of course, we can use JSDoc, but to be honest, JSDoc is not reliable when it comes to type-checking. The reason is, JSDoc is a documentation tool, not a compiler or type checker.&lt;/p&gt;

&lt;h2&gt;
  
  
  Object-Oriented Programming
&lt;/h2&gt;

&lt;p&gt;TypeScript fully supports object oriented programming. Class field modifiers are a recent addition to JavaScript. Thanks to V8 engine, we can use it in Node without any polyfill. TypeScript had these features for a long time. It supports class field modifiers such as &lt;code&gt;private&lt;/code&gt;, &lt;code&gt;public&lt;/code&gt; and &lt;code&gt;protected&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Autocompletion
&lt;/h2&gt;

&lt;p&gt;Almost all of the popular IDE and text editors have great support for TypeScript. With TypeScript, you get better support for auto-completion of code. And most of the time, editors would highlight any type of errors before you even run the program.&lt;/p&gt;

&lt;p&gt;Again, JSDoc can be a replacement for this. And it is what we used when TypeScript was not so popular. But both of these tools have their own tasks to accomplish.&lt;/p&gt;

&lt;h2&gt;
  
  
  Transpile Code
&lt;/h2&gt;

&lt;p&gt;TypeScript can compile to many versions of ECMAScript. You can use all the latest features of JavaScript happily and still be stress-free about supporting the older environments.&lt;/p&gt;

&lt;p&gt;Point to be noted here: TypeScript does not polyfill anything. It converts code from one version of JavaScript to another. For example, if your codebase has some code snippets that the &lt;code&gt;target&lt;/code&gt; version does not support, TypeScript will convert the code so that it is compitable with the older version of ECMAScript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isTrue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Boolean&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;hello&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isTrue&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;not set to a boolean value&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we choose &lt;code&gt;ES3&lt;/code&gt; as target, above snippet will be compiled 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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use strict&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;isTrue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;hello&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nx"&gt;isTrue&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;isTrue&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;isTrue&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;not set to a boolean value&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;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;There are certainly some drawbacks of using TypeScript over JavaScript. But those drawbacks are so negligible that they don’t even count.&lt;/p&gt;

&lt;p&gt;TypeScript produces a maintainable codebase. Maybe it won’t matter when the codebase is small. But in the long run, we get a codebase that could be maintained by People without losing their sanity. If someone in the team has never used a statically-typed language before, they will need some training.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>web</category>
    </item>
    <item>
      <title>Session Management in Vim</title>
      <dc:creator>Abdus Azad</dc:creator>
      <pubDate>Mon, 26 Oct 2020 10:52:18 +0000</pubDate>
      <link>https://dev.to/abdus/session-management-in-vim-2ekh</link>
      <guid>https://dev.to/abdus/session-management-in-vim-2ekh</guid>
      <description>&lt;p&gt;If you ask me about the most underrated feature in Vim, my answer would be&lt;br&gt;
'Session Management' straightaway! Just like any other "modern" editors, Vim&lt;br&gt;
does support sessions.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is a Session
&lt;/h2&gt;

&lt;p&gt;Before I go in-depth, let me explain what exactly is a Session in Vim. Simply&lt;br&gt;
put(from &lt;code&gt;:help session&lt;/code&gt;): A Session keeps the Views for all windows, plus the global settings.&lt;/p&gt;

&lt;p&gt;An example of a session could be: If I have opened a project and worked for an&lt;br&gt;
hour, and then closed it. My Vim session would be one hour long.&lt;/p&gt;

&lt;p&gt;Sessions in Vim are not persistent by default. One has to make it persistent.&lt;br&gt;
Most people do not know about it because they probably have never felt the&lt;br&gt;
need for it.&lt;/p&gt;

&lt;p&gt;I was one of those people who didn't feel the need for storing sessions, until&lt;br&gt;
recently. And I am not ashamed of it. It just happens... mostly because, we&lt;br&gt;
don't need it &lt;em&gt;yet&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Importance of Session
&lt;/h2&gt;

&lt;p&gt;To answer the question 'How a persistent Session is Useful', let's find out what&lt;br&gt;
we lack without it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Time&lt;/strong&gt;. Yes! Imagine, you are working on a project, and for some reason,
you closed Vim. So when you open it again, you gotta recreate those perfectly sized windows, open files or config options etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context&lt;/strong&gt;. It's not easy to remember which file you were editing, the last time you have worked on a project.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, what if I say that you could boot into Vim without losing any of the&lt;br&gt;
previous windows, tabs etc? not even the cursor location. That would be&lt;br&gt;
great, is not it?&lt;/p&gt;

&lt;p&gt;That's where persistent session comes into action. It enables Vim to load&lt;br&gt;
the last session, much like what we see in editors like Visual Studio Code.&lt;/p&gt;
&lt;h2&gt;
  
  
  Storing Sessions
&lt;/h2&gt;

&lt;p&gt;There are multiple techniques one may use to handle Sessions. I will, however,&lt;br&gt;
talk about the one I use.&lt;/p&gt;

&lt;p&gt;First, I let Vim look for any existing session files. If one exists for the&lt;br&gt;
current session, Vim would update it automatically when I close Vim. The Reason&lt;br&gt;
I don't let Vim save Sessions for which no session file exists, because that&lt;br&gt;
makes me counter-productive. For example, I needed to edit a config file, say,&lt;br&gt;
&lt;code&gt;.vimrc&lt;/code&gt; from my &lt;code&gt;$HOME&lt;/code&gt; directory. Had I enabled auto-create session file, a&lt;br&gt;
new session file for &lt;code&gt;$HOME&lt;/code&gt; directory will be created, which I obviously don't&lt;br&gt;
want. That session does not make any sense.&lt;/p&gt;

&lt;p&gt;So, if a session file is not created automatically, how do I create it then? &lt;br&gt;
Well, it's really simple. I defined a command for creating new Sessions, called&lt;br&gt;
&lt;code&gt;SessCreate&lt;/code&gt; using &lt;a href="http://vimdoc.sourceforge.net/htmldoc/usr_41.html"&gt;Vim Language&lt;/a&gt;.&lt;br&gt;
Now, I can simply call this command from inside Vim whenever I need it.&lt;/p&gt;

&lt;p&gt;Let me show you how I did it.&lt;/p&gt;
&lt;h3&gt;
  
  
  Snippet
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;fu&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; SessionCreate&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="nb"&gt;isdirectory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"~/.vim/sessions"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nb"&gt;execute&lt;/span&gt; &lt;span class="s2"&gt;"call mkdir(expand('~/.vim/sessions', 'p'))"&lt;/span&gt;
  &lt;span class="k"&gt;endif&lt;/span&gt;
  &lt;span class="nb"&gt;execute&lt;/span&gt; &lt;span class="s1"&gt;'mksession ~/.vim/sessions/'&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="k"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;getcwd&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="m"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'.vim'&lt;/span&gt;
&lt;span class="k"&gt;endfunction&lt;/span&gt;

command SessCreate &lt;span class="k"&gt;call&lt;/span&gt; SessionCreate&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Explanation:
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;isdirectory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"~/.vim/sessions"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="nb"&gt;execute&lt;/span&gt; &lt;span class="s2"&gt;"call mkdir(expand('~/.vim/sessions', 'p'))"&lt;/span&gt;
&lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Check if a directory &lt;code&gt;$HOME/.vim.sessions&lt;/code&gt; exist. If not, create it with&lt;br&gt;
&lt;code&gt;execute "call mkdir(expand('~/.vim/sessions', 'p'))"&lt;/code&gt;. This is the directory&lt;br&gt;
where sessions are stored. An alternate location for storing session is the&lt;br&gt;
project directory itself. But that is not something I want to use, as not&lt;br&gt;
everyone uses Vim. So, this would be an added bloat for them.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;call&lt;/code&gt; in Vim Script is used to call a function. &lt;code&gt;mkdir()&lt;/code&gt; is used to create a&lt;br&gt;
new directory. &lt;code&gt;p&lt;/code&gt; is a flag that can be passed to &lt;code&gt;mkdir()&lt;/code&gt; so that it creates&lt;br&gt;
parent directories as and when necessary. Lastly, &lt;code&gt;expand()&lt;/code&gt; is used to expand&lt;br&gt;
any Shell expandables. Here, it converts &lt;code&gt;~&lt;/code&gt; to &lt;code&gt;/home/username&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="nb"&gt;execute&lt;/span&gt; &lt;span class="s1"&gt;'mksession ~/.vim/sessions/'&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="k"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;getcwd&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="m"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'.vim'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;mksession&lt;/code&gt; is a built-in command for creating a session from the current Vim state.&lt;br&gt;
It saves the created session in &lt;code&gt;~/.vim/sessions/DIR_NAME.vim&lt;/code&gt;. Here, the&lt;br&gt;
&lt;code&gt;DIR_NAME&lt;/code&gt; is the working directory where Vim is opened. So, session for&lt;br&gt;
&lt;code&gt;~/Projects/github/awesome-vim&lt;/code&gt; would be saved into&lt;br&gt;
&lt;code&gt;~/.vim/sessions/awesome-vim.vim&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Saving a Session in Existing Session File
&lt;/h3&gt;

&lt;p&gt;Now, it's time for some automation. Check out the following code snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;fu&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; SessionSave&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;filewritable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'~/.vim/sessions/'&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="k"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;getcwd&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="m"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'.vim'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nb"&gt;execute&lt;/span&gt; &lt;span class="s1"&gt;'mksession! ~/.vim/sessions/'&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="k"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;getcwd&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="m"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'.vim'&lt;/span&gt;
  &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;span class="k"&gt;endfunction&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function checks whether the existing session file is writable. And save&lt;br&gt;
the latest session if true. That's it. The exclamation mark(&lt;code&gt;!&lt;/code&gt;) is for overwriting&lt;br&gt;
the previous session.&lt;/p&gt;
&lt;h3&gt;
  
  
  Restoring a Session
&lt;/h3&gt;

&lt;p&gt;Finally, when I open Vim again, I want saved buffer(if any) to be restored.&lt;br&gt;
Following function is responsible for this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;fu&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; SessionRestore&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;session_file &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'~/.vim/sessions/'&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="k"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;getcwd&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="m"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'.vim'&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;filereadable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;session_file&lt;span class="p"&gt;))&lt;/span&gt;
    echo session_file
    &lt;span class="nb"&gt;execute&lt;/span&gt; &lt;span class="s1"&gt;'source ~/.vim/sessions/'&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;  &lt;span class="k"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;getcwd&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="m"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'.vim'&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;bufexists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;bufnr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'$'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;bufwinnr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;-1&lt;/span&gt;
          exec &lt;span class="s1"&gt;'sbuffer '&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;
        &lt;span class="k"&gt;endif&lt;/span&gt;
      &lt;span class="k"&gt;endfor&lt;/span&gt;
    &lt;span class="k"&gt;endif&lt;/span&gt;
  &lt;span class="k"&gt;endif&lt;/span&gt;
&lt;span class="k"&gt;endfunction&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let me explain what it does exactly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;session_file &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'~/.vim/sessions/'&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="k"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;getcwd&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="m"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'.vim'&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;filereadable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;session_file&lt;span class="p"&gt;))&lt;/span&gt;
  echo session_file
  &lt;span class="nb"&gt;execute&lt;/span&gt; &lt;span class="s1"&gt;'source ~/.vim/sessions/'&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;  &lt;span class="k"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;getcwd&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="m"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'.vim'&lt;/span&gt;
&lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, check if the file is readable. There's no point in sourcing it if Vim&lt;br&gt;
can't access it. Then simply source it to Vim. That's it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;bufexists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;bufnr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'$'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;bufwinnr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;-1&lt;/span&gt;
      exec &lt;span class="s1"&gt;'sbuffer '&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="k"&gt;l&lt;/span&gt;
    &lt;span class="k"&gt;endif&lt;/span&gt;
  &lt;span class="k"&gt;endfor&lt;/span&gt;
&lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;bufexists()&lt;/code&gt; function checks if any&lt;br&gt;
&lt;a href="https://vim.fandom.com/wiki/Buffers"&gt;buffer&lt;/a&gt; exists. &lt;code&gt;bufnr()&lt;/code&gt; returns all&lt;br&gt;
available buffers. ...and so on. Read more about them using &lt;code&gt;:help FUNC_NAME&lt;/code&gt;&lt;br&gt;
in Vim.&lt;/p&gt;

&lt;p&gt;So, that's it. Persistent Sessions makes our life dramatically easier when using&lt;br&gt;
Vim (or NeoVim, GVim whatever flavour you use).&lt;/p&gt;

&lt;p&gt;P.S.: I am a new Vim user. I am open to suggestions. Feel free to suggest&lt;br&gt;
anything that would make use Vim in a more productive way!!&lt;/p&gt;

</description>
      <category>vim</category>
      <category>linux</category>
      <category>neovim</category>
      <category>editor</category>
    </item>
    <item>
      <title>Fiber: a Super Minimal Hugo Blog Theme</title>
      <dc:creator>Abdus Azad</dc:creator>
      <pubDate>Sun, 30 Aug 2020 02:03:21 +0000</pubDate>
      <link>https://dev.to/abdus/fiber-a-super-minimal-hugo-blog-theme-17g4</link>
      <guid>https://dev.to/abdus/fiber-a-super-minimal-hugo-blog-theme-17g4</guid>
      <description>&lt;p&gt;Hello DEV community! I am here to brag about my recently launched Hugo theme!&lt;/p&gt;

&lt;p&gt;In short, &lt;strong&gt;Fiber&lt;/strong&gt; is a Hugo theme for the Minimalists. It features a Clean and Simple UI™. It also has a 'Notes' section so that you won't have to ditch nicely written notes from your personal website. It's your choice anyway.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Simple and Clean UI™&lt;/li&gt;
&lt;li&gt;Shortcodes - Currently, it has two custom shortcodes. Both embed ASCIINema Casts and CanIUse data respectively into the page. (Of course, I plan to add more)&lt;/li&gt;
&lt;li&gt;Code Highlighting&lt;/li&gt;
&lt;li&gt;Click-to-copy Codes (maintains indentations)&lt;/li&gt;
&lt;li&gt;Notes - Uses &lt;a href="https://roughnotation.com/"&gt;rough-notations&lt;/a&gt; to spice things up&lt;/li&gt;
&lt;li&gt;Most importantly; this theme just works, without throwing any errors!!!&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Screenshots
&lt;/h2&gt;

&lt;p&gt;Check out some screenshots! Or you can check this &lt;a href="https://abdus.xyz"&gt;theme in action here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OmOBBClc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/0u3xptnvm96yhz2qwzpq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OmOBBClc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/0u3xptnvm96yhz2qwzpq.png" alt="hugo theme fiber"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Uz_gzYTa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6a83nfsuy6k1dujlds5l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Uz_gzYTa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6a83nfsuy6k1dujlds5l.png" alt="hugo theme fiber"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--URXRaUqL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2asl8vhxt1y3h311350b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--URXRaUqL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2asl8vhxt1y3h311350b.png" alt="hugo theme fiber"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ucPf_NxK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8it9m85hup0g8loxawt3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ucPf_NxK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8it9m85hup0g8loxawt3.png" alt="hugo theme fiber"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--O6fU-wYC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/x2vgr8mn6sk72fgtlfov.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--O6fU-wYC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/x2vgr8mn6sk72fgtlfov.png" alt="hugo theme fiber"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---4CAuF5Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/41i6gg2kpxujxuhzg9hh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---4CAuF5Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/41i6gg2kpxujxuhzg9hh.png" alt="hugo theme fiber"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(&lt;em&gt;ignore those red lines at the bottom. they are coming from window manager&lt;/em&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Use
&lt;/h2&gt;

&lt;p&gt;Since you made it up to here, I would assume you are interested in trying this theme out! Installation and Usage are documented in &lt;a href="https://github.com/abdus/hugo-theme-fiber"&gt;Readme&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It would be great if you &lt;strong&gt;Star this &lt;a href="https://github.com/abdus/hugo-theme-fiber"&gt;project on Github&lt;/a&gt;&lt;/strong&gt;. This step is completely optional though ;)&lt;/p&gt;

&lt;p&gt;Have a good day!&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>hugo</category>
      <category>theme</category>
    </item>
    <item>
      <title>Using Github Profile Readme as 'Twitter-like' Feed</title>
      <dc:creator>Abdus Azad</dc:creator>
      <pubDate>Thu, 20 Aug 2020 01:16:55 +0000</pubDate>
      <link>https://dev.to/abdus/using-github-profile-readme-as-twitter-like-feed-25k4</link>
      <guid>https://dev.to/abdus/using-github-profile-readme-as-twitter-like-feed-25k4</guid>
      <description>&lt;p&gt;I had this weird idea of using GitHub profile README as Twitter-like(well,&lt;br&gt;
Mastodon TBH) feed! There was no specific reason for doing so. I roughly&lt;br&gt;
thought it would boost my Mastodon profile(which is quite new at the moment)&lt;br&gt;
reach.&lt;/p&gt;

&lt;p&gt;Another reason was to see how far I could go with limited tools (as Github&lt;br&gt;
ReadMe does not support JavaScript yet).&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating those Cards
&lt;/h2&gt;

&lt;p&gt;There was only one thing to figure out. How to create beautiful status cards&lt;br&gt;
with limited CSS! I knew I could use SVG and make whatever I want. But not&lt;br&gt;
all browser supports every feature of SVG yet. So, generating and&lt;br&gt;
storing SVG codes as images may not always work.&lt;/p&gt;

&lt;p&gt;Since GitHub has introduced workflows(better be late than never), I chose to&lt;br&gt;
render SVG on a webpage and convert them to PNG, all in Server-side.&lt;/p&gt;

&lt;p&gt;This way, I am assured that SVG would be rendered in the latest browser and&lt;br&gt;
converted PNG. But how do I do it?&lt;/p&gt;

&lt;p&gt;There is a package called &lt;a href="https://github.com/puppeteer/puppeteer"&gt;Puppeteer&lt;/a&gt; in the NPM registry. This library gives&lt;br&gt;
the user a way to control Chromium/Firefox browser programmatically. This,&lt;br&gt;
by default, runs browser in headless mode. So, the user would be able to run it&lt;br&gt;
without a Desktop Environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting 'Toots' from Mastodon
&lt;/h2&gt;

&lt;p&gt;If you don't know about Mastodon, you can think of it as Open-Source Twitter!&lt;br&gt;
&lt;a href="https://joinmastodon.org/"&gt;Read more about Mastodon&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Mastodon have an API to fetch public toots of any profile without using an&lt;br&gt;
API key. The response is in JSON, so parsing it was quite simple.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Biggest surprise: If I add a Middot (·) somewhere inside SVG, loading image&lt;br&gt;
won't work! It throws an encoding error.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Installing Font
&lt;/h2&gt;

&lt;p&gt;After pushing the initial version to GitHub, I noticed that the font I was&lt;br&gt;
using locally was not available in Github Workflows environment. So, I had to&lt;br&gt;
install them manually. Although I could simply add a font CDN using &lt;code&gt;style&lt;/code&gt;&lt;br&gt;
tag within SVG, why not do it the Linux' way? :P&lt;/p&gt;

&lt;p&gt;Installing font through command-line as just three simple steps.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;download font as a zip archive&lt;/li&gt;
&lt;li&gt;extract font files to &lt;code&gt;~/.fonts&lt;/code&gt; using &lt;code&gt;unzip&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;run &lt;code&gt;fc-cache -f -v&lt;/code&gt; to manually update the font cache&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Writing Workflow Steps
&lt;/h2&gt;

&lt;p&gt;I set-up the workflow to run in two events. First is, when I push something to&lt;br&gt;
the repository. And second is, on every hour (using a Cronjob). This way, I won't&lt;br&gt;
have to worry about updating ReadMe manually when I post a new toot.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting up Node and NPM was done by an action called &lt;a href="https://github.com/actions/setup-node"&gt;&lt;code&gt;setup-node&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Installing required font was done by a custom bash &lt;a href="https://github.com/abdus/abdus/blob/57372e8c9321a3c0d1141098483a0c2a648315a6/.github/workflows/publish.yml#L21-L26"&gt;script I wrote&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Finally, the &lt;a href="https://github.com/abdus/abdus/blob/master/index.mjs"&gt;image creation script&lt;/a&gt; was run using Node, commit the changes, and push them back to GitHub.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the work is done here!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conslusion
&lt;/h2&gt;

&lt;p&gt;Sure, this thing was just for fun. But I learnt quite a few new things.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I can't use Middot(or similar characters) within an SVG tag. Now I know
what to look for when there's an encoding issue.&lt;/li&gt;
&lt;li&gt;I understand how &lt;code&gt;action/checkout&lt;/code&gt; works. This will help me write better
workflows in future.&lt;/li&gt;
&lt;li&gt;I learnt about some SVG tags. For example, &lt;code&gt;switch&lt;/code&gt; and &lt;code&gt;foreignObject&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you liked this, I would be happy if you &lt;strong&gt;star 🌟 &lt;a href="https://github.com/abdus/abdus"&gt;this repository&lt;/a&gt;&lt;/strong&gt;.&lt;br&gt;
You can follow me on Mastodon. My handle is &lt;strong&gt;@&lt;a href="mailto:abdus@linuxrocks.online"&gt;abdus@linuxrocks.online&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>github</category>
      <category>mastodon</category>
      <category>twitter</category>
    </item>
    <item>
      <title>Terminating DOM Operations at will: 'AbortController' in JavaScript</title>
      <dc:creator>Abdus Azad</dc:creator>
      <pubDate>Sun, 26 Jul 2020 16:21:49 +0000</pubDate>
      <link>https://dev.to/abdus/terminating-dom-operations-at-will-abortcontroller-in-javascript-1icm</link>
      <guid>https://dev.to/abdus/terminating-dom-operations-at-will-abortcontroller-in-javascript-1icm</guid>
      <description>&lt;p&gt;&lt;strong&gt;AbortController&lt;/strong&gt; is an interface which provides a way for terminating one or&lt;br&gt;
more web request as and when desired.&lt;/p&gt;

&lt;p&gt;This generally means that a request can be terminated by a user whenever needed,&lt;br&gt;
irrespective of whether the operation is finished or not.&lt;br&gt;
&lt;code&gt;AbortSignal&lt;/code&gt; can be implemented in any web platform API which uses&lt;br&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise"&gt;&lt;code&gt;Promise&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  The API
&lt;/h2&gt;

&lt;p&gt;AbortController provides a few things for users to implement it effectively in&lt;br&gt;
code. At the time of writing this, the constructor would return an instance which&lt;br&gt;
contains a method &lt;code&gt;AbortController.abort()&lt;/code&gt; and a property &lt;br&gt;
&lt;code&gt;AbortController.signal&lt;/code&gt;(read-only).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;AbortController.signal&lt;/code&gt; - Returns a &lt;code&gt;AbortSignal&lt;/code&gt; instance&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AbortController.abort()&lt;/code&gt; - Aborts a DOM Request&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  AbortSignal
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;AbortController.signal&lt;/code&gt; returns an instance of type &lt;code&gt;AbortSignal&lt;/code&gt; which &lt;br&gt;
represents the current state of the AbortController instance.&lt;br&gt;
It has a read-only property &lt;code&gt;AbortSignal.aborted&lt;/code&gt;. Type of property &lt;code&gt;aborted&lt;/code&gt;&lt;br&gt;
is &lt;code&gt;Boolean&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;AbortSignal&lt;/code&gt; is also responsible for communicating with DOM as an Event Listener&lt;br&gt;
can be attached to it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Using AbortController
&lt;/h2&gt;

&lt;p&gt;To use AbortController in a &lt;code&gt;Promise&lt;/code&gt;, one must adhere to a few rules.&lt;br&gt;
&lt;a href="https://dom.spec.whatwg.org/#abortcontroller-api-integration"&gt;Source&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Function should accept &lt;code&gt;AbortSignal&lt;/code&gt; through a &lt;code&gt;signal&lt;/code&gt; property. For example:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;abortThis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;signal&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="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&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="c1"&gt;// function body&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;When method &lt;code&gt;aborted()&lt;/code&gt; is called, &lt;strong&gt;reject the Promise&lt;/strong&gt; with a
&lt;code&gt;DOMException&lt;/code&gt; &lt;code&gt;AbortError&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;DOMException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aborted by user&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;ABORT_ERR&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;ul&gt;
&lt;li&gt; Abort immediately if the &lt;code&gt;aborted&lt;/code&gt; flag on &lt;code&gt;AbortSignal&lt;/code&gt; is set to &lt;code&gt;true&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Browser Support
&lt;/h2&gt;

&lt;p&gt;Despite being a relatively new API, browser support for AbortController is&lt;br&gt;
quite awesome! All major browser &lt;em&gt;fully&lt;/em&gt; supports it. Following is a chart&lt;br&gt;
from &lt;em&gt;Can I Use&lt;/em&gt;.&lt;/p&gt;





&lt;p&gt;&amp;lt;div&lt;br&gt;
  class="ciu_embed"&lt;br&gt;
  data-feature="abortcontroller"&lt;br&gt;
  data-periods="future_1,current,past_1,past_2"&lt;br&gt;
  data-accessible-colours="false"&lt;/p&gt;

&lt;blockquote&gt;

&lt;p&gt;&lt;br&gt;
  Data on support for the abortcontroller feature across the major&lt;br&gt;
    browsers&lt;br&gt;
  &lt;/p&gt;
&lt;br&gt;

&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Examples
&lt;/h2&gt;

&lt;p&gt;Following are a few examples of &lt;code&gt;AbortController&lt;/code&gt; API. First one is using &lt;code&gt;fetch&lt;/code&gt;&lt;br&gt;
API. On the second example, I will try to implement it in a &lt;code&gt;Promise&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Using Fetch API
&lt;/h3&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;controller&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;AbortController&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;signal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// fetch a URL&lt;/span&gt;
&lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://jsonplaceholder.typicode.com/todos/1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;ok&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&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;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&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="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&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="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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// driver code&lt;/span&gt;
&lt;span class="nx"&gt;setTimeout&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="c1"&gt;// abort network request if it takes&lt;/span&gt;
  &lt;span class="c1"&gt;// more than a second&lt;/span&gt;
  &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The above code allows a network request to run for &lt;code&gt;500ms&lt;/code&gt;. If data has been&lt;br&gt;
fetched within that period, it would return JSON representation of the response.&lt;br&gt;
Otherwise, it would abort the request.&lt;/p&gt;
&lt;h3&gt;
  
  
  Implementing using Promise
&lt;/h3&gt;

&lt;p&gt;In this section, I will try to implement &lt;code&gt;AbortController&lt;/code&gt; for a function which&lt;br&gt;
returns Promise. Should be quite easy and straightforward.&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="cm"&gt;/* this function would return a Promise
 * which would resolve with value `hello`
 * after 4s
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;abortTask&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;signal&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="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&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="c1"&gt;// 1. check if it's already aborted&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;signal&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aborted&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;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;DOMException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;`signal` is in `aborted` state&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;ABORT_ERR&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// wait for 4s&lt;/span&gt;
    &lt;span class="nx"&gt;setTimeout&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;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 2. add a listener to `signal` to check its state&lt;/span&gt;
    &lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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;abort&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// reject promise when signal.aborted changes to `true`&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;DOMException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aborted by user&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;ABORT_ERR&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;



&lt;span class="cm"&gt;/* DRIVER CODE */&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// just so that I could re-use it&lt;/span&gt;


&lt;span class="c1"&gt;// when `signal.aborted` is `false`&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;abortController_1&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;AbortController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;abortController_1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;abortTask&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// hello&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&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="nx"&gt;console&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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


&lt;span class="c1"&gt;// when `signal.aborted` is `true`&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;abortController_2&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;AbortController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;abortController_2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;abortController_2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;abortTask&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&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="nx"&gt;console&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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// err&lt;/span&gt;


&lt;span class="c1"&gt;// when user calls AbortController.abort()&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;abortController_3&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;AbortController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;abortController_3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// abort task in 2s&lt;/span&gt;
&lt;span class="nx"&gt;setTimeout&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;abortController_3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;abortTask&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&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="nx"&gt;console&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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// err&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>javascript</category>
      <category>html</category>
      <category>dom</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Get Your Own Heroku - a Guide on How to Run a Custom 'Platform as a Service' for deploying Apps</title>
      <dc:creator>Abdus Azad</dc:creator>
      <pubDate>Sun, 26 Apr 2020 07:02:06 +0000</pubDate>
      <link>https://dev.to/thisisabdus/get-your-own-heroku-a-guide-on-how-to-run-a-custom-platform-as-a-service-for-deploying-apps-n4h</link>
      <guid>https://dev.to/thisisabdus/get-your-own-heroku-a-guide-on-how-to-run-a-custom-platform-as-a-service-for-deploying-apps-n4h</guid>
      <description>&lt;p&gt;Heroku is a fantastic platform for Node.js developers. It made deployment of Node.js apps super easier. But obviously. it have so many limitations on free-tier, which makes it less ideal for deploying certain kind of projects, like a  telegram bot etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Idea
&lt;/h2&gt;

&lt;p&gt;I was having a pretty similar issue. I needed to host a bot. Initially, it was in Heroku, but due to the fact that every apps on Heroku free tier goes for sleep after inactivity of around 30 minutes. This, generally, is not a problem for websites, but bots won't work. There is always a delay on bot response.&lt;/p&gt;

&lt;p&gt;First, I thought I would build my own Heroku-like platform. But it's not really easy. So, I went off with an open-source 'Platform as a Service' software.&lt;/p&gt;

&lt;p&gt;Likely, there are many such open-sourced products available. One of them is  &lt;strong&gt;&lt;a href="https://github.com/caprover/caprover"&gt;CapRover&lt;/a&gt;&lt;/strong&gt;. &lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;Docker-based deployment. Each of the deployed app would have their own isolated space.&lt;/li&gt;
&lt;li&gt;Support for &lt;code&gt;Dockerfile&lt;/code&gt;. A &lt;code&gt;Dockerfile&lt;/code&gt; would maximize the possibilities of what you could do with the deployments. &lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Nothing much required, really! All you need is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A VPS to host CapRover. Preferably DigitalOcean
It should also have a Linux OS installed. Ubuntu is preferred. &lt;/li&gt;
&lt;li&gt;Basic Linux Shell Skills for installing required applications.&lt;/li&gt;
&lt;li&gt;A Domain Name&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Initial Server Setup
&lt;/h3&gt;

&lt;p&gt;If you are using Digital Ocean, first you need to create a droplet. Digital Ocean have a nice guide on &lt;a href="https://www.digitalocean.com/docs/droplets/how-to/create/"&gt;how-to setup a droplet&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Once you are done creating a Droplet, it's time to update the system. To do that, you need to access your droplet using SSH. &lt;a href="https://www.digitalocean.com/docs/droplets/how-to/connect-with-ssh/"&gt;This tutorial&lt;/a&gt; would help you do that. &lt;/p&gt;

&lt;p&gt;After connecting to droplet via SSH, update and upgrade the system using &lt;code&gt;sudo apt update &amp;amp;&amp;amp; sudo apt upgrade&lt;/code&gt;. Note that, these commands are for Ubuntu. &lt;/p&gt;

&lt;p&gt;We also need a couple of other software in order to get our CapRover server up and running. We will be installing them one by one.&lt;/p&gt;

&lt;h4&gt;
  
  
  Docker
&lt;/h4&gt;

&lt;p&gt;CapRover is built on top of Docker. So, it's an essential essential software. To install docker, checkout the official &lt;a href="https://docs.docker.com/engine/install/ubuntu/"&gt;Docker documentation for Ubuntu&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You may need to add the current user to &lt;code&gt;docker&lt;/code&gt; group. To do so, run &lt;code&gt;sudo usermod -aG docker &amp;lt;user_name&amp;gt;&lt;/code&gt;. Otherwise, you will get a docker error.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Node.js and NPM
&lt;/h4&gt;

&lt;p&gt;Yeah, these Node thing is everywhere these days :/ But anyways, it should be relatively easier to install. Note that, by default Ubuntu repository have &lt;code&gt;node v8.x.x&lt;/code&gt;. We need at least &lt;code&gt;v10.x.x&lt;/code&gt;. So to install &lt;code&gt;node v13.x.x&lt;/code&gt; via NodeSource:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sL&lt;/span&gt; https://deb.nodesource.com/setup_13.x | &lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; bash -
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then run &lt;code&gt;apt-get install&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; nodejs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To confirm that you have Node installed, run &lt;code&gt;node -v&lt;/code&gt; from terminal. &lt;/p&gt;

&lt;h4&gt;
  
  
  NPM
&lt;/h4&gt;

&lt;p&gt;It's possible that NPM was installed along with Node.js. You can verify that using &lt;code&gt;npm -v&lt;/code&gt;. In case it is not installed, install it from Ubuntu repository using &lt;code&gt;sudo apt install npm&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;By default, NPM needs &lt;code&gt;sudo&lt;/code&gt; to install global packages, which is not recommended. To change this behavior, change &lt;code&gt;prefix&lt;/code&gt; in NPM config. Run &lt;code&gt;npm config set prefix dir_name&lt;/code&gt;(replace &lt;code&gt;dir_name&lt;/code&gt; with a directory name where you want to have npm packages). You also, need to add &lt;code&gt;dir_name/bin&lt;/code&gt; to your PATH variable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Domain Setup
&lt;/h3&gt;

&lt;p&gt;By now, you should have a static IP address assigned to your Digital Ocean droplet. If you have a domain name purchased, you need to point it to your server IP address using A record. For example: you want &lt;code&gt;captain.yourdomain.com&lt;/code&gt; as your app host. You need to setup two different a records.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cap              A         3.23.76.12
*.captain        A         3.23.76.12
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;At this point, your server is ready to host CapRover. You may additionally need to allow some ports in order to make CapRover work. You can allow them using &lt;code&gt;ufw&lt;/code&gt; command in Ubuntu.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;ufw allow 80,443,3000,996,7946,4789,2377/tcp&lt;span class="p"&gt;;&lt;/span&gt; ufw allow 7946,4789,2377/udp&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note that, this command must run in root shell.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install CapRover and CapRover CLI
&lt;/h2&gt;

&lt;p&gt;Thanks to the devloper of CapRover, it's super easy to install. All we need is to run one command, sit back and watch it installing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 80:80 &lt;span class="nt"&gt;-p&lt;/span&gt; 443:443 &lt;span class="nt"&gt;-p&lt;/span&gt; 3000:3000 &lt;span class="nt"&gt;-v&lt;/span&gt; /var/run/docker.sock:/var/run/docker.sock &lt;span class="nt"&gt;-v&lt;/span&gt; /captain:/captain caprover/caprover
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once the CapRover installation is done, visit &lt;code&gt;cap.domainname.com:3000&lt;/code&gt; to verify if CapRover is working. We also need to install CapRover CLI in order to manage deployment, sertup server etc. To install CapRover from NPM, run &lt;code&gt;npm i -g caprover&lt;/code&gt;. Once installed, run &lt;code&gt;caprover serversetup&lt;/code&gt;, and follow the interactive command prompt.&lt;/p&gt;

&lt;p&gt;At this point, you have a CapRover instance running successfully. Check this guide for various &lt;a href="https://caprover.com/docs/deployment-methods.html"&gt;deployment methods&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Before deploying a project, make sure to create an &lt;code&gt;app&lt;/code&gt; using the Web GUI. Otherwise, you won't be able to deploy.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For more information about CapRover and it's configurations, check out its &lt;strong&gt;&lt;a href="https://caprover.com/docs"&gt;official docs&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;Having a self-managed PaaS could be very handy. Following are a few reasons I choose to go with a self-managed PaaS for hosting apps.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I would be saving money. 
  Generally, if I go for Heroku non-free tier, I would be paying a lot of money compared to what I pay now.&lt;/li&gt;
&lt;li&gt;Shared Resources.
  Server resources won't get wasted because each and every app would be able to access resources from the same resource pool. So, let's say, I have 2 GB of RAM. And I need only 1 GB to host XYZ webapp. Now, I can use the remaining amount of RAM to spin-up a new instance ABC webapp.&lt;/li&gt;
&lt;li&gt;Support for [insert techstack name]
  Since, CapRover uses docker to deploy a new instance, I can basically run apps built using any back-end technologies. And write how to deploy it using a Dockerfile. I have so much flexibility now.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The only downside I could think of is, I have to look after the server. This is won't be a big deal, thanks to AWS ❤️ &lt;/p&gt;

</description>
      <category>paas</category>
      <category>heroku</category>
      <category>node</category>
      <category>vps</category>
    </item>
    <item>
      <title>Securely sending Emails from static sites with a 3rd party API</title>
      <dc:creator>Abdus Azad</dc:creator>
      <pubDate>Thu, 07 Nov 2019 18:30:00 +0000</pubDate>
      <link>https://dev.to/thisisabdus/securely-sending-emails-from-static-sites-with-a-3rd-party-api-304c</link>
      <guid>https://dev.to/thisisabdus/securely-sending-emails-from-static-sites-with-a-3rd-party-api-304c</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This are the exact same steps I am following to make &lt;a href="https://abdus.xyz#message"&gt;this form&lt;/a&gt; work. If you find any flaws, I should be the first one to know :)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I have been looking for a way to send emails and/or other data from a static site using a third party mailing API. There are a few awesome services for sending mails but none of them are ‘secure’. By secure, I mean to say that whatever a person is sending to me through a mailing API is delivered as plain text. That means, anyone having access to the API server could see any mail sent to me via their API. And I don’t want to setup my own back-end just to send emails, either.&lt;/p&gt;

&lt;p&gt;The solution to this problem is pretty simple! Encrypt all data before you are sending using a public key which belongs to you. And whenever it is delivered to you, decrypt with your public key.&lt;/p&gt;

&lt;h2&gt;
  
  
  Explanation
&lt;/h2&gt;

&lt;p&gt;Okay. Here you may have a question, what the hell is a &lt;strong&gt;key&lt;/strong&gt;? To answer that, a key is an unique id using which a person could encrypt a message and decrypt it on demand later on.&lt;/p&gt;

&lt;p&gt;So, what is the benefit? Well, a lot of benefits! First, no other person than you could ever look into it(unless you share your private key). It won’t let anyone modify the message which is being sent to you in midway.&lt;/p&gt;

&lt;p&gt;To encrypt/cipher the plain text message, we will be using &lt;strong&gt;Public Key Encryption&lt;/strong&gt;. So, before moving forward, let’s learn about a few related terms related to cryptography which I will be using throughout the post.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Private Key&lt;/strong&gt; : It is a cryptographic key used for decryption. By nature, it is a secret key and should only be with you. Once you think you lost the key or it get compromised, time to get a new one. And invalidate previous public and private key.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Public Key&lt;/strong&gt; : It comes with your private key, as a pair. This key is used to do encryption so that the private key could decrypt. This key can freely be shared with anyone. A message which is encrypted with a public key must be decrypted using the private key of that pair. I have my &lt;a href="https://abdus.xyz/public-key.txt"&gt;public key here&lt;/a&gt;. Send encrypted message haha..&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fingerprint&lt;/strong&gt; : A fingerprint is a short version(consists bytes) of a longer public key. It is used to simplify key management in certain apps. It’s generated by applying a &lt;a href="https://en.wikipedia.org/wiki/Cryptographic_hash_function"&gt;cryptographic hash function&lt;/a&gt; in public key. My fingerprint is &lt;code&gt;FA20 8736 8166 715F E3C1  60C6 F2AE 28CC C8CA FB9A&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;Steps to implement:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We will generate a key pair for us. So that, we can encrypt/decrypt a message.&lt;/li&gt;
&lt;li&gt;Encrypt message using our own public key.&lt;/li&gt;
&lt;li&gt;Send message from our static site using a mail delivery API.&lt;/li&gt;
&lt;li&gt;Once the API delivers the message to us, decrypt using private key.&lt;/li&gt;
&lt;li&gt;That should be enough! Let’s see how it goes.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Generate a Key Pair
&lt;/h3&gt;

&lt;p&gt;To handle encryption, we would be using OpenPGP. OpenPGP is an encryption standard derived from PGP. GnuPG(&lt;code&gt;gpg&lt;/code&gt;) is a software which implements OpenPGP. Generally GnuPG comes pre-installed. If you don’t have it installed, &lt;a href="https://www.gnupg.org/download/index.html"&gt;download it from here&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Pretty Good Privacy (PGP) is an encryption program that provides cryptographic privacy and authentication for data communication. PGP is used for signing, encrypting, and decrypting texts, e-mails, files, directories, and whole disk partitions and to increase the security of e-mail communications. Phil Zimmermann developed PGP in 1991. - &lt;a href="https://en.wikipedia.org/wiki/Pretty_Good_Privacy"&gt;wikipedia&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Generate a new Key from command line: Type &lt;code&gt;gpg --full-gen-key&lt;/code&gt; in your terminal, hit enter and follow the on-screen instruction.&lt;/li&gt;
&lt;li&gt;To find out fingerprint of your key, run &lt;code&gt;gpg --fingerprint&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;To export public key(you have to), run &lt;code&gt;gpg --armor --export FINGERPRINT &amp;gt; public-key.txt&lt;/code&gt;. This will generate an ASCII armored public key and save it in &lt;code&gt;public-key.txt&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Encrypt Data
&lt;/h3&gt;

&lt;p&gt;Now that we have our key, we can go ahead and geneate encrypted text using the public key. To encryt/decrypt, we would be using a library called &lt;code&gt;openPGP.js&lt;/code&gt;(developed by Signal). You can simply add this library to a project using CDN.&lt;/p&gt;

&lt;p&gt;Let’s start with writing some codes.&lt;/p&gt;

&lt;h4&gt;
  
  
  Create a form in HTML
&lt;/h4&gt;

&lt;p&gt;Copy following HTML inside &lt;code&gt;index.html&lt;/code&gt;(create file in project root)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"mail@abdus.xyz"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;br&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Abdus"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;br&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;textarea&lt;/span&gt;
        &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt;
        &lt;span class="na"&gt;cols=&lt;/span&gt;&lt;span class="s"&gt;"30"&lt;/span&gt;
        &lt;span class="na"&gt;rows=&lt;/span&gt;&lt;span class="s"&gt;"10"&lt;/span&gt;
        &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Your awesome message"&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;gt;&amp;lt;/textarea&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;gt;&amp;lt;br&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"Encrypt and Send"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script
      &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdnjs.cloudflare.com/ajax/libs/openpgp/4.6.2/openpgp.min.js"&lt;/span&gt;
      &lt;span class="na"&gt;integrity=&lt;/span&gt;&lt;span class="s"&gt;"sha256-txcrHjb7Yt1zrebRnGkk5OwDkoBrvJTjvJx5b7qBtWc="&lt;/span&gt;
      &lt;span class="na"&gt;crossorigin=&lt;/span&gt;&lt;span class="s"&gt;"anonymous"&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"assets/js/main.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Also copy following JavaScript inside &lt;code&gt;assets/js/main.js&lt;/code&gt;(create in project root)&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;PUBLIC_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`PUT YOUR PUBLIC KEY HERE(copy it from public-key.txt we generated earlier)`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&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;enc_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openpgp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;openpgp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fromText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;armor&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="c1"&gt;// export as ascii armored text&lt;/span&gt;
    &lt;span class="na"&gt;publicKeys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openpgp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readArmored&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PUBLIC_KEY&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;sendMail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;enc_message&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="c1"&gt;// send the mail&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;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&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;submit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&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="c1"&gt;// dom manipulation&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sender&lt;/span&gt; &lt;span class="o"&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="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;email&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;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;message&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;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="c1"&gt;// prevent page from reload on form submit&lt;/span&gt;
  &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// finally call our encrypt function&lt;/span&gt;
  &lt;span class="nx"&gt;encrypt&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;sender&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; &amp;lt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt; \n\n\n &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&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="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;sendMail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;encrypted_message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// here, we will make a POST request to formspree&lt;/span&gt;
  &lt;span class="c1"&gt;// so that formspree could deliver our data&lt;/span&gt;
  &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://formspree.io/YOUR_FORMSPREE_ID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no-cors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;encrypted_message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&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="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Above JavaScript is pretty much self-explanatory. You shouldn’t have much problem with it. If you face any issue, let me know using &lt;a href="////abdus.xyz#user-email"&gt;this form&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Also, we need a &lt;a href="https://formspree.io"&gt;Formspree&lt;/a&gt; account. This is an API to deliver our form data/email. It’s easy to create an account in Formspree. You can do that.&lt;/p&gt;

&lt;h3&gt;
  
  
  Decrypt a message
&lt;/h3&gt;

&lt;p&gt;Once you recieve the message through Formspree, it’s time to decrypt and see what is inside it. To do that, we would be using command line gpg client. Before decrypting, save your encrypted text in a file and name it &lt;code&gt;something.pgp&lt;/code&gt;. Then finally, run &lt;code&gt;gpg --decrypt something.pgp&lt;/code&gt;(assuming something.pgp is in current working directory). The output with be piped to standard output, i.e. (mostly) terminal/cmd window. To save it in a file, add this flag to the command: &lt;code&gt;--output something.txt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you prefer a GUI application, you’ll find many open-source applications for free. Just make sure it implements the OpenPGP standards.&lt;/p&gt;

&lt;p&gt;That’s it! By this time, you should have an encrypted email which is delivered securely with the help of a third-party website from your static site.&lt;/p&gt;

&lt;h3&gt;
  
  
  Footnote
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;This encrypting process does not sign the document.&lt;/li&gt;
&lt;li&gt;It’s always better to use your own server.&lt;/li&gt;
&lt;li&gt;Never disclose your private key. Never.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>cryptography</category>
      <category>publickey</category>
      <category>encryption</category>
      <category>fingerprint</category>
    </item>
    <item>
      <title>How to Load a Website Faster</title>
      <dc:creator>Abdus Azad</dc:creator>
      <pubDate>Mon, 28 Jan 2019 18:30:00 +0000</pubDate>
      <link>https://dev.to/thisisabdus/how-to-load-a-website-faster-33gh</link>
      <guid>https://dev.to/thisisabdus/how-to-load-a-website-faster-33gh</guid>
      <description>&lt;p&gt;Page Load-time is an important factor for any kind of websites. The lower the load-time, higher the site traffic and low &lt;a href="https://en.wikipedia.org/wiki/Bounce_rate"&gt;bounce rate&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you don’t know what a page load time is, it’s the time taken by a browser to render a webpage. This process includes: making a request to the server, downloading the resources, processing DOM elements and rendering.&lt;/p&gt;

&lt;p&gt;To decrease a website’s page load time, you have to follow certain things while building/creating a website.&lt;/p&gt;

&lt;h2&gt;
  
  
  Place scripts just before the closing body tag
&lt;/h2&gt;

&lt;p&gt;No matter what a script does, it should always be placed at end of &amp;lt;body&amp;gt;. i.e. the closing &amp;lt;/body&amp;gt; tag. Scripts are generally huge in size and costs browser some extra time to load it. Moreover, you don’t want to execute any scripts before the DOM even loads, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Minify
&lt;/h2&gt;

&lt;p&gt;Yes, minify stylesheets and scripts. &lt;em&gt;minify&lt;/em&gt; is a process of removing whitespace and unwanted characters from your code. It will help you reduce the size of files so that browser could download it faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don’t use too many redirects
&lt;/h2&gt;

&lt;p&gt;Whenever we redirect a link, it takes an extra request to the server. For example, if you are loading some resources from &lt;em&gt;example.com&lt;/em&gt; which redirects to &lt;em&gt;example-2.com&lt;/em&gt;. You are forcing the client(browser) to make an extra request. So, minimize the use of redirected links.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use CDN
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;CDN&lt;/strong&gt; or Content Delivery Network help you reduce the server load and serve pages based on user’s location. For example, if you are somewhere in the US and using a CDN, the website would be served from the nearest server available and not from the original server. This method helps you cut-down the distance travelled by resources.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Splitting
&lt;/h2&gt;

&lt;p&gt;This might look something new to you. This helps you load only the code you require to render the very first instance of any website. So, if you have a big CSS file which contains many selectors which don’t need during initial render, eliminate them or create a new CSS file and load them on a later stage.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;em&gt;async&lt;/em&gt; and &lt;em&gt;defer&lt;/em&gt; for scripts
&lt;/h2&gt;

&lt;p&gt;if you have some scripts which you don’t need immediately, just &lt;code&gt;defer&lt;/code&gt; them. &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;defer&lt;/code&gt; tells the browser to load these scripts on a later stage. Example,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;async&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"example.com"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;defer&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"example.com"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>loadtime</category>
      <category>website</category>
    </item>
    <item>
      <title>A light colored Dev badge</title>
      <dc:creator>Abdus Azad</dc:creator>
      <pubDate>Thu, 19 Apr 2018 12:28:01 +0000</pubDate>
      <link>https://dev.to/abdus/a-light-colored-dev-logo-1njf</link>
      <guid>https://dev.to/abdus/a-light-colored-dev-logo-1njf</guid>
      <description>&lt;p&gt;I need a light colored badge to render on my website because my website's having a dark background. So, the logo doesn't look as expexted on my website. And I think everyone with a dark themed website facing this issue.&lt;/p&gt;

&lt;p&gt;So, It would be great for us if Dev.to provide a light colored badge to showcase on our website. &lt;/p&gt;

</description>
      <category>logo</category>
      <category>helpme</category>
      <category>meta</category>
    </item>
  </channel>
</rss>
