<?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>Forem: Skcript</title>
    <description>The latest articles on Forem by Skcript (@skcript).</description>
    <link>https://forem.com/skcript</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%2Forganization%2Fprofile_image%2F134%2F9f0a096a-b22e-4541-b8eb-174aa4bb2e9a.jpg</url>
      <title>Forem: Skcript</title>
      <link>https://forem.com/skcript</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/skcript"/>
    <language>en</language>
    <item>
      <title>Building Gmail Addons</title>
      <dc:creator>Varun Raj</dc:creator>
      <pubDate>Mon, 30 Nov 2020 12:17:59 +0000</pubDate>
      <link>https://forem.com/skcript/building-gmail-addons-1e22</link>
      <guid>https://forem.com/skcript/building-gmail-addons-1e22</guid>
      <description>&lt;p&gt;Addons and integrations are the most impactful features when it comes to building SaaS products. The reason being the more your tool integrates with others, the more reach and user base it gets. Basically when you integrate with popular tools or products like Gmail which is already used by millions of people, your product just gets super charged.&lt;/p&gt;

&lt;p&gt;Today, you’ll learn how to build one such cool add-on for your app, and yes, it's gonna run on Gmail.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: The Setup
&lt;/h3&gt;

&lt;p&gt;One new thing about this, is that you don't need to worry about your local environment when developing, as everything happens inside your browser on a platform called &lt;strong&gt;Google App Scripts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Navigate to &lt;a href="http://script.google.com/home"&gt;http://script.google.com/home&lt;/a&gt; and create a new project from the sidebar option.&lt;/p&gt;

&lt;p&gt;&lt;a href="/svrmedia/heroes/image5-29.png" class="article-body-image-wrapper"&gt;&lt;img src="/svrmedia/heroes/image5-29.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A new editor window opens where you’re going to spend most of your time building the addon.&lt;/p&gt;

&lt;p&gt;&lt;a href="/svrmedia/heroes/image8-9.png" class="article-body-image-wrapper"&gt;&lt;img src="/svrmedia/heroes/image8-9.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the “&lt;strong&gt;Untitled project&lt;/strong&gt;” to edit the project name to your app name, in my case I'm going to create an addon to show the latest news.&lt;/p&gt;

&lt;p&gt;&lt;a href="/svrmedia/heroes/image4-37.png" class="article-body-image-wrapper"&gt;&lt;img src="/svrmedia/heroes/image4-37.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you name the project, you need to create a manifest file. It's more like the manifest file we create for our Chrome Apps or an Outlook Plugin. It contains meta information, scope to access, and other such information about the app.&lt;/p&gt;

&lt;p&gt;Click on “View → Show manifest file” from the menu bar and it opens a new file named “&lt;strong&gt;appsscript.json&lt;/strong&gt;”&lt;/p&gt;

&lt;p&gt;&lt;a href="/svrmedia/heroes/image7-16.png" class="article-body-image-wrapper"&gt;&lt;img src="/svrmedia/heroes/image7-16.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The contents of the manifest file is in JSON format and will hold the below information by default,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timeZone"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Asia/Kolkata"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"exceptionLogging"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"STACKDRIVER"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"runtimeVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"V8"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Configuration
&lt;/h3&gt;

&lt;p&gt;Now that we’ve our base of the addon, let's configure it to work in Gmail.&lt;/p&gt;

&lt;p&gt;Under the dependencies section of the manifest add the gmail service with the following config,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"enabledAdvancedServices"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"userSymbol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Gmail"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"serviceId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"gmail"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"v1"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After defining that we’re going to use the Gmail service, we need to define the behaviour, appearance of the addon inside Gmail.&lt;/p&gt;

&lt;p&gt;Create a new block with the key “gmail” in the manifest root where you enter all the config of Gmail.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"gmail"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Today's News"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"logoUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"https://www.gstatic.com/images/icons/material/system/1x/receipt_black_24dp.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"contextualTriggers"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"unconditional"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;

        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

        &lt;/span&gt;&lt;span class="nl"&gt;"onTriggerFunction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"startApp"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"primaryColor"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"#F47041"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"secondaryColor"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"#2E8B57"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"TRUSTED_TESTER_V2"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the config above, the main part to notice is the &lt;em&gt;contextualTriggers&lt;/em&gt; section. It’s an array of functions.&lt;/p&gt;

&lt;p&gt;Currently we’re going to use a simple trigger &lt;em&gt;onTriggerFunction&lt;/em&gt;, which as the name explains will get triggered when the app is opened in the addons section of Gmail. This will call a function defined in any of our .gs files.&lt;/p&gt;

&lt;p&gt;There’s also other cosmetic configurations like name, icon and colors.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Creating the UI
&lt;/h3&gt;

&lt;p&gt;The UI is also created by the script in Gmail addon. Open the code.gs and create a new function called &lt;em&gt;startApp&lt;/em&gt;. This function will be triggered when we open the app from the addons section.&lt;/p&gt;

&lt;p&gt;Note: In app script the function names are unique no matter which file you write it.&lt;/p&gt;

&lt;p&gt;Lets create a simple card in the UI&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;startApp&lt;/span&gt;&lt;span class="p"&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;card&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;CardService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newCardBuilder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;NewsListCard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CardService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newCardHeader&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;setTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;News&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;sectionNews&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;CardService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newCardSection&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;sectionNews&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CardService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newTextParagraph&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;News of the day&lt;/span&gt;&lt;span class="dl"&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;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sectionNews&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;build&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;Save the file and lets try to run and see the result&lt;/p&gt;

&lt;p&gt;To test the addon, click on “Publish → Deploy from manifest” in the menu bar,&lt;/p&gt;

&lt;p&gt;&lt;a href="/svrmedia/heroes/image10-7.png" class="article-body-image-wrapper"&gt;&lt;img src="/svrmedia/heroes/image10-7.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This brings up another window that lists all the versions of your addon. Click on the &lt;em&gt;Install add-on&lt;/em&gt; button in the “Latest Version (Head) Version 0” since this is the development version.&lt;/p&gt;

&lt;p&gt;&lt;a href="/svrmedia/heroes/image6-21.png" class="article-body-image-wrapper"&gt;&lt;img src="/svrmedia/heroes/image6-21.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once installed, you can open your Gmail account (the one where the app script project was created) to see the addon in the sidebar.&lt;/p&gt;

&lt;p&gt;&lt;a href="/svrmedia/heroes/image2-52.png" class="article-body-image-wrapper"&gt;&lt;img src="/svrmedia/heroes/image2-52.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the first run, you need to authorize access to the app to use it. After authorization you can see the cards that we created in the script.&lt;/p&gt;

&lt;p&gt;&lt;a href="/svrmedia/heroes/image1-55.png" class="article-body-image-wrapper"&gt;&lt;img src="/svrmedia/heroes/image1-55.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Loading Data From API
&lt;/h3&gt;

&lt;p&gt;We’ve set up the basic card section to show the basic static information of the app. Now let's try to pull in some data from remote API to show in the addons section. Currently I'm going to use a public API for the demo purpose, but you can also use your own APIs to pull your app’s data.&lt;/p&gt;

&lt;p&gt;For this demo I'm going to use &lt;a href="https://newsapi.org/"&gt;&lt;strong&gt;https://newsapi.org/&lt;/strong&gt;&lt;/a&gt; API since it has a free plan and public.&lt;/p&gt;

&lt;p&gt;Sign up for the News API Service and get your API token.&lt;/p&gt;

&lt;p&gt;We’ll be using the UrlFetchApp class to make external API calls. For writing clean code, I’ve created a new file called “APIs.gs” from the file menu&lt;/p&gt;

&lt;p&gt;&lt;a href="/svrmedia/heroes/image11-4.png" class="article-body-image-wrapper"&gt;&lt;img src="/svrmedia/heroes/image11-4.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Write the below function to make an API call to the new API with your token in the payload to get the news articles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getNews&lt;/span&gt;&lt;span class="p"&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;UrlFetchApp&lt;/span&gt;&lt;span class="p"&gt;.&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="s2"&gt;http://newsapi.org/v2/top-headlines?country=us&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="s2"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;muteHttpExceptions&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;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;X-Api-Key&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="s2"&gt;YOUR NEWS API KEY HERE&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="nx"&gt;Logger&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getContentText&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;responseText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getContentText&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;responseJSON&lt;/span&gt; &lt;span class="o"&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;responseText&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;responseJSON&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 our API call is ready, let's call it and render the data in the UI. Open your Code.gs file and add the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;startApp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// .....&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;newsResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getNews&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;news&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newsResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;articles&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;var&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;news&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;var&lt;/span&gt; &lt;span class="nx"&gt;newsItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;news&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="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;newsBlock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;CardService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newDecoratedText&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newsItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;sectionNews&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newsBlock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// …..&lt;/span&gt;
  &lt;span class="c1"&gt;// .....&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sectionNews&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;build&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;This will call the &lt;em&gt;getNews&lt;/em&gt; function and render each item into the sectionNews Card section.&lt;/p&gt;

&lt;p&gt;Save the file and refresh the addon from your Gmail addon panel.&lt;/p&gt;

&lt;p&gt;&lt;a href="/svrmedia/heroes/image3-38.png" class="article-body-image-wrapper"&gt;&lt;img src="/svrmedia/heroes/image3-38.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After refreshing you’ll get the list of news title in the addon screen&lt;/p&gt;

&lt;p&gt;&lt;a href="/svrmedia/heroes/image9-9.png" class="article-body-image-wrapper"&gt;&lt;img src="/svrmedia/heroes/image9-9.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And we’ve created a simple addon which can list your daily news inside Gmail! This can be your app’s addon too. The best part is that most of your business users can adopt it so quickly which helps your app grow faster.&lt;/p&gt;

&lt;p&gt;In the next article, I’ll write about how to use user credentials to get the current user info and also session storage. Until then, keep exploring! :D&lt;/p&gt;

</description>
      <category>gmail</category>
      <category>addons</category>
      <category>integrations</category>
      <category>googleappscript</category>
    </item>
    <item>
      <title>Red, Green, Refactor.</title>
      <dc:creator>Sathish</dc:creator>
      <pubDate>Wed, 25 Nov 2020 12:14:25 +0000</pubDate>
      <link>https://forem.com/skcript/red-green-refactor-462h</link>
      <guid>https://forem.com/skcript/red-green-refactor-462h</guid>
      <description>&lt;p&gt;Red, Green, Refactor is a TDD approach or framework that the developers use to build the test suite first, write the implementation code, and refactor the code once the test suite passes.&lt;/p&gt;

&lt;p&gt;According to Computer Scientist Robert C Martin who advocates TDD, we can write effective code only when there is a test case to pass and the only time we have the time to write tests is before writing the implementation code. The feasible way to do so is to use the Red, Green, Refactor approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are they?
&lt;/h2&gt;

&lt;p&gt;We can compartmentalize writing code into 3 segments as the title suggests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Red&lt;/strong&gt; - Write a test suite without the implementation code, making it fail.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Green&lt;/strong&gt; - Now, we can write the implementation code, just so the test suite passes. Nothing more, nothing less.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Refactor&lt;/strong&gt; - After the test suite passes, we can look for ways to optimize.&lt;/p&gt;

&lt;p&gt;...rinse &amp;amp; repeat. This happens until we have a fully functional implementation code.&lt;/p&gt;

&lt;p&gt;Robert C. Martin (“Uncle Bob”) provides a concise set of rules for practicing TDD.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write production code only to pass a failing unit test.&lt;/li&gt;
&lt;li&gt;Write no more of a unit test than sufficient to fail (compilation failures are failures).&lt;/li&gt;
&lt;li&gt;Write no more production code than necessary to pass the one failing unit test.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How is it done?
&lt;/h2&gt;

&lt;p&gt;We can see how it’s done by looking at an implementation of the Fibonacci problem with recursion. We’ll use the &lt;a href="https://repl.it/@jest/jest-playground" rel="noopener noreferrer"&gt;Jest playground&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Iteration 1
&lt;/h3&gt;

&lt;p&gt;We have two JavaScript files, one is &lt;code&gt;fib.js&lt;/code&gt; to contain the implementation code, &lt;code&gt;fib.test.js&lt;/code&gt; to contain the test suites. As an overkill, you can start without the function defined in &lt;code&gt;fib.js&lt;/code&gt;. Let me keep the post as short as possible.&lt;/p&gt;

&lt;h4&gt;
  
  
  Red
&lt;/h4&gt;

&lt;p&gt;Since we are solving the problem with recursion, we need to first define our base case first. Which is, if n is lesser than 2, we need to return n.&lt;/p&gt;

&lt;p&gt;Let’s first write the test suite for the base case, which will be the following,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fib&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./fib&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;base case , n &amp;lt; 2&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="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;n = 1 will return 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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fib&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="nf"&gt;toBe&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We expect this to fail since we don’t have any implementation code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fskcript.com%2Fsvrmedia%2Fheroes%2Fimage1-54.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fskcript.com%2Fsvrmedia%2Fheroes%2Fimage1-54.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Green
&lt;/h4&gt;

&lt;p&gt;We now need to write the implementation code for the base case. Remember, only the code that’s needed to make our test suite pass.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&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;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;n&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;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, this code satisfies our test suite. What’s next? Let’s look at refactoring the above code.&lt;/p&gt;

&lt;h4&gt;
  
  
  Refactor
&lt;/h4&gt;

&lt;p&gt;From the above implementation code, we don’t have anything much to refactor so let’s move to Iteration 2.&lt;/p&gt;

&lt;h3&gt;
  
  
  Iteration 2
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Red
&lt;/h4&gt;

&lt;p&gt;Now we have our base case, let’s look at the next step which is to write the recursive code. Let’s extend our test suite to test the recursive case.&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="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;recursive case , n &amp;gt;= 2&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="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;n = 8 will return 21&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="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;n = 15 will return 610&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="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;610&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;Now, that we extended our test suite, let’s see the failing test case result which is as follows,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fskcript.com%2Fsvrmedia%2Fheroes%2Fimage3-37.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fskcript.com%2Fsvrmedia%2Fheroes%2Fimage3-37.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you have guessed, this is because, in our implementation code, we check if n is lesser than 2 and return n. It doesn’t currently handle the case where n is greater than or equal to 2.&lt;/p&gt;

&lt;h4&gt;
  
  
  Green
&lt;/h4&gt;

&lt;p&gt;We’ll now write the implementation code so that our test suite passes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&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;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;n&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&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="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With recursion, we have written the implementation code to handle the case where n &amp;gt;= 2. We’ll now have Green, where our test suite passes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fskcript.com%2Fsvrmedia%2Fheroes%2Fimage2-51.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fskcript.com%2Fsvrmedia%2Fheroes%2Fimage2-51.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Refactor
&lt;/h4&gt;

&lt;p&gt;What could we possibly do here to refactor the above code? Not much, but as a cosmetic update, we can remove the unwanted braces and the else part since we are returning in the if part. After refactoring, our code will look like the following,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&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;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&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;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&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="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Iteration 3
&lt;/h3&gt;

&lt;p&gt;Well, there’s no Iteration 3 since we have a fully functional module. So, it ends here.&lt;/p&gt;

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

&lt;p&gt;This approach might look time-consuming at first, but once we get a hold of it, it can be employed to write effective testable code that will make everyone’s life easier, while building a more robust solution than you otherwise would have.&lt;/p&gt;

&lt;p&gt;Ok, bye!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fskcript.com%2Fsvrmedia%2Fheroes%2Fimage4-36.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fskcript.com%2Fsvrmedia%2Fheroes%2Fimage4-36.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tdd</category>
      <category>javascript</category>
      <category>testing</category>
    </item>
    <item>
      <title>Building and Using Custom Entities in Dialogflow</title>
      <dc:creator>Varun Raj</dc:creator>
      <pubDate>Mon, 28 Sep 2020 16:28:36 +0000</pubDate>
      <link>https://forem.com/skcript/building-and-using-custom-entities-in-dialogflow-1g38</link>
      <guid>https://forem.com/skcript/building-and-using-custom-entities-in-dialogflow-1g38</guid>
      <description>&lt;p&gt;In this article, I'll cover how we can create custom entities that cover your business requirements.&lt;/p&gt;

&lt;p&gt;Before proceeding, I strongly recommend you to read my previous article in case if you missed it: &lt;a href="https://www.skcript.com/svr/building-a-serverless-telegram-chatbot-with-dialogflow-and-firebase-functions/"&gt;https://www.skcript.com/svr/building-a-serverless-telegram-chatbot-with-dialogflow-and-firebase-functions/&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What are the entities? a quick recap.&lt;a href="https://www.skcript.com/svr/building-and-using-custom-entities-in-dialogflow/#what-are-the-entities-a-quick-recap"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Entities as something similar to your data types in a programming language that helps you define what sort of data is stored in a variable. Here, entities in chatbot language are nothing but the pattern or the meaning we classify certain parts or elements of the conversation.&lt;/p&gt;

&lt;p&gt;For example, in the below message, the user is asking for weather information in the city of Dubai. So, when configuring the chatbot we classify "Dubai" as the city, and post the training the bot will understand any city.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image6-15.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jMugAdAb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image6-15.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the limitation with inbuilt entities?&lt;a href="https://www.skcript.com/svr/building-and-using-custom-entities-in-dialogflow/#what-is-the-limitation-with-inbuilt-entities"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;In Dialogflow, the inbuilt entities are trained based on the generic scenarios like date, city, and other standard units. But in most cases, we've to create our entities to satisfy the business requirements.&lt;/p&gt;

&lt;p&gt;For an instance consider the below statement in an HR chatbot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image4-29.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UgBZgoFD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image4-29.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, we can easily train the bot to extract the start date and end date since it's a very general information class. But the challenge comes when we try to extract the type of leave. The type of leave is information related to a specific requirement. Leave type could change between one organization to another.&lt;/p&gt;

&lt;p&gt;These are the cases that can't be solved with built-in entities and we need to depend on custom entities.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do we create custom entities?&lt;a href="https://www.skcript.com/svr/building-and-using-custom-entities-in-dialogflow/#how-do-we-create-custom-entities"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Let's take our leave application use case for this article. To Dialogflow classify the leave type, we need to create a new entity called "Leave".&lt;/p&gt;

&lt;p&gt;Navigate to the Entities section in the sidebar of the project console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image3-27.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4ST0CfEI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image3-27.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here you get to see all the custom entities that you created in your project, let's create our first custom entity.&lt;/p&gt;

&lt;p&gt;If you notice, the Dialogflow gives us the option to create the Entity and various items under that entity. This works more like your enum in programming as I mentioned earlier.&lt;/p&gt;

&lt;p&gt;In our case, under the leave types, we've sick leave, annual leave, and vacation leave. So I create those under the entity items. Also providing more synonyms will help the bot to train for understanding better.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image1-40.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MjyCE8lr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image1-40.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can simply save after you created the required items for the entity. Post the training we can start using these new custom entities in the intent configuration page similar to system entities.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image5-23.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FnKwmfE1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image5-23.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let's ask the bot question to see if it can classify all the leaves properly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image7.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JkArRfXE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image7.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Similar to this you can create any number of custom entities based on your requirements and use them together as well in the intent. Here is a small example from another chatbot project where I've used more than one custom entity in a statement.&lt;/p&gt;

&lt;p&gt;Here both the facility attribute as well as facility entities are custom built for this hotel chatbot where the user asks for details of a facility in the hotel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image2-41.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nNal-wWx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image2-41.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dialogflow</category>
      <category>chatbot</category>
      <category>serverless</category>
      <category>firebase</category>
    </item>
    <item>
      <title>Webpack with React Typescript</title>
      <dc:creator>Sooraj (PS)</dc:creator>
      <pubDate>Sun, 23 Aug 2020 13:41:43 +0000</pubDate>
      <link>https://forem.com/skcript/webpack-with-react-typescript-1i93</link>
      <guid>https://forem.com/skcript/webpack-with-react-typescript-1i93</guid>
      <description>&lt;p&gt;Ever wondered if there is a way to just tie up all your code into one single module for easy usage. If so, in this article I will show you how to bundle all your code into a single javascript module that you can easily use in any other project.&lt;/p&gt;

&lt;p&gt;So you write a web app with multiple dependencies like jquery etc, images and multiple styles and then you look at the code and think, “If I am going to use this code in the client then I will need to import each and every module along with the application javascript files. Great!”. This is where webpack comes to the rescue.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Webpack?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage7-1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage7-1.gif" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Webpack&lt;/strong&gt; is a static module bundler for JavaScript applications. As you can see from the name, Web + pack - means creating a single package for the web. So, it takes all your code, runs through your code, transpile into the correct format, and gives you full control to bundle all your files into a single or a few files to easily run on the browser. In this article, we will build and configure a React TS app using Webpack to load on the client.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up the project:
&lt;/h3&gt;

&lt;h4&gt;
  
  
  We will be creating the project from scratch.
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Initialize package.json&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The first step is to create a folder and initialize that with npm init for the package.json file. For this project, we will follow the default options. To create a default package.json file, run the following command from the folder on your terminal or vscode terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init &lt;span class="nt"&gt;--y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage4-24.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage4-24.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The --y command will choose the default values for all the fields.&lt;/p&gt;

&lt;p&gt;You can also run.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But, this will take you through all the fields manually and ask you for a value. You can skip each value by pressing enter.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage3-4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage3-4.gif" width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
Me when I say yes to each field.&lt;/p&gt;

&lt;p&gt;I prefer the --y param because it lets you create the same file with one command rather than each field.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Add the necessary packages to the package.json&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We will be adding the following to the package.json file&lt;/p&gt;

&lt;p&gt;Developer Dependencies&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;babel&lt;/strong&gt; (core, env, react, ts and loader) as the transcompiler.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;cross-env&lt;/strong&gt; for setting environment variables across cross platforms.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;html-webpack-plugin&lt;/strong&gt; to create HTML files and serve your bundle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;serve&lt;/strong&gt; to serve the single page created.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;terser-webpack-plugin&lt;/strong&gt; to minify your bundled javascript.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;typescript&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;@types/necessary packages&lt;/strong&gt; for the type-checked versions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;webpack&lt;/strong&gt; (core, cli, dev-server) as a webpack package.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dependencies&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;react&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;react-dom&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;package.json&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"react"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^16.12.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"react-dom"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^16.12.0"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@babel/core"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^7.7.7"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@babel/preset-env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^7.7.7"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@babel/preset-react"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^7.7.4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@babel/preset-typescript"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^7.7.7"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@types/node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^12.12.5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@types/react"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^16.9.11"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@types/react-dom"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^16.9.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"babel-loader"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^8.0.6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"cross-env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^6.0.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"html-webpack-plugin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^3.2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"serve"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^11.3.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"terser-webpack-plugin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^2.3.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"typescript"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^3.7.4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"webpack"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.41.5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"webpack-cli"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^3.3.10"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"webpack-dev-server"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^3.10.1"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Add the necessary scripts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For our webpack to bundle everything we need to add the scripts to either create a dev server or a production build. Add the following under scripts in package.json.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cross-env NODE_ENV=development webpack-dev-server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cross-env NODE_ENV=production webpack"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"serve dist"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;cross-env&lt;/strong&gt; will make sure that the environment variable setting is consistent across all the platforms. We will create 2 scripts, 1 for the development and 1 for production. We will use the &lt;strong&gt;webpack-dev-server&lt;/strong&gt; for the development bundle and &lt;strong&gt;webpack&lt;/strong&gt; for the production build. The bundle will be created in the dist folder and we can &lt;strong&gt;serve&lt;/strong&gt; the dist folder in the development or production builds.&lt;/p&gt;

&lt;p&gt;This is the setup for package.json. After doing this run &lt;strong&gt;npm install&lt;/strong&gt; to install all the dependencies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Adding the babel configuration file&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now for the babel compiler to work in sync with webpack, we need to add the configuration for babel. Create a file called ‘&lt;strong&gt;.babelrc&lt;/strong&gt;’ and add the following in the file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"presets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"@babel/env"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@babel/react"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@babel/typescript"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will just tell babel to use the env, react and typescript presets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5: Add the tsconfig for the typescript configurations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We need to create a tsconfig.json file in our root directory for typescript configurations. If you have typescript installed, the easiest way to generate this file is to use&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tsc &lt;span class="nt"&gt;--init&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will add a tsconfig.json to your root directory with all the possible configurations. For this project, we will create a tsconfig.json file manually and add simple configuration options like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"es6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"commonjs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"jsx"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"react"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"moduleResolution"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"strict"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"noEmit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"allowJs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"skipLibCheck"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"isolatedModules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"esModuleInterop"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"include"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"src"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can take a look at all possible options in the typescript documentation for further details.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6: Webpack Configuration&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is one of the most confusing configuration options that developers come across in projects. Let us first create a file called webpack.config.js in the root directory and add the following.&lt;/p&gt;

&lt;p&gt;First, we need to import our plugins. The 2 main plugins we will be using here are the &lt;strong&gt;html-webpack plugin&lt;/strong&gt; and the &lt;strong&gt;terser-webpack-plugin.&lt;/strong&gt; We will also import the path package to read the files from their relative path. Import them as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="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="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;HtmlWebpackPlugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;html-webpack-plugin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TerserWebpackPlugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;terser-webpack-plugin&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;Next, we will create the configuration object as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isProd&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;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&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="nx"&gt;isProd&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;production&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="s2"&gt;development&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./src/index.tsx&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;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dist&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bundle.js&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;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.js&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="s2"&gt;.jsx&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="s2"&gt;.ts&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="s2"&gt;.tsx&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;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;tsx&lt;/span&gt;&lt;span class="se"&gt;?&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;use&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;babel-loader&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;exclude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/node_modules/&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="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HtmlWebpackPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./src/index.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;index.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;body&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isProd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;optimization&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;minimizer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TerserWebpackPlugin&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;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;devServer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;9000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;open&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;hot&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;compress&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;stats&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;errors-only&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;overlay&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="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The most important options in webpack are &lt;strong&gt;entry, output,&lt;/strong&gt; and &lt;strong&gt;module&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;entry&lt;/strong&gt; specifies the entry point of the application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;output&lt;/strong&gt; specifies where the bundle has to be built to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;modules&lt;/strong&gt; specify the test cases to classify the files and use the corresponding loaders for those files. In this case, we have used the babel-loader on the files with &lt;strong&gt;.tsx&lt;/strong&gt; extension.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We have also added some ‘dev’ vs ‘prod’ conditions to either run on the dev server if the environment specified is &lt;strong&gt;development&lt;/strong&gt; or minify the bundle if it is &lt;strong&gt;production&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 7: Adding React&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Finally, we need to add a react in the code. Just add an src folder in the root directory and create the following files.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;index.html&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;index.tsx&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;App.tsx&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add the following code to the files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;index.html&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Webpack with React TS&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;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;&lt;strong&gt;index.tsx&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&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;react&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;render&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;react-dom&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;App&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;./App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;App.tsx&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&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;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Webpack&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;cool&lt;/span&gt;&lt;span class="o"&gt;!&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 8: Run the webpack servers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;npm run dev:&lt;/strong&gt; This will use the webpack dev-server to create a dev server and will watch for your code changes and be recompiled every time you make a change.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage2-33.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage2-33.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;npm run build:&lt;/strong&gt; This command will build your code and generate a single bundle file and insert it into the html file generated.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage6-11.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage6-11.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;npm run start:&lt;/strong&gt; This command will run the serve package which will use the dist folder to create a static page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage1-34.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage1-34.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage5-20.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage5-20.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that’s it. We have our application with a webpack configured and ready to go. The main reason for writing this article is to make the people understand how the webpack works or any other generic bundling tool works. A lot of people would say to just use a template and get it done within 5 - 10 minutes, but the whole point is to understand what you are doing with it. I have had a lot of issues with this because I used to use templates, but once I got to know how the actual flow works, it was really interesting.&lt;/p&gt;

</description>
      <category>react</category>
      <category>beginners</category>
      <category>webpack</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Building a Serverless Telegram Chatbot with Dialogflow and Firebase Functions</title>
      <dc:creator>Varun Raj</dc:creator>
      <pubDate>Mon, 17 Aug 2020 03:18:55 +0000</pubDate>
      <link>https://forem.com/skcript/building-a-serverless-telegram-chatbot-with-dialogflow-and-firebase-functions-cl3</link>
      <guid>https://forem.com/skcript/building-a-serverless-telegram-chatbot-with-dialogflow-and-firebase-functions-cl3</guid>
      <description>&lt;p&gt;A couple of years back, I was struggling to manage my documents - tried all available cloud storages and even thumb drives. Nothing came handy and also searching documents in cloud storage was never easier for me. So, I decided to build a chatbot which can send me documents whenever I ask for it. That's when I built Nila, my first personal chatbot.&lt;/p&gt;

&lt;p&gt;Often people ask me how I built Nila. They were surprised when I said it is not a rule-based chatbot and it can understand my language. So, later I added more features to it, but that's a different story.&lt;/p&gt;

&lt;p&gt;Since it created a lot of interest among my friends and community, I thought of writing an article about how I built it. And, here it is.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Tech Stack&lt;a href="https://www.skcript.com/svr/building-a-serverless-telegram-chatbot-with-dialogflow-and-firebase-functions/#the-tech-stack"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;I wanted it to be a very thin setup and without major maintenance. As soon as this requirement was decided, the first thing that popped into my mind was serverless architecture. The best thing about it is that I don't have to maintain a server - deploying code was a lot easier compared to server infrastructure. The next question that came to my mind was where to store all this information. This is where my 'Swiss army knife' of product development comes into play. In addition, I decided to use Firebase for everything other than the NLP part.&lt;/p&gt;

&lt;p&gt;So, the final tech stack was drilled down to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Firebase Cloud Functions - Backend Processing&lt;/li&gt;
&lt;li&gt; Firebase Storage - File Storage&lt;/li&gt;
&lt;li&gt; Firebase Firestore - For Database&lt;/li&gt;
&lt;li&gt; Dialogflow - For NLP&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Infrastructure&lt;a href="https://www.skcript.com/svr/building-a-serverless-telegram-chatbot-with-dialogflow-and-firebase-functions/#the-infrastructure"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The next step was to come up with an infrastructure to build an architecture design that becomes the core. Since the entire system is broken down into distributed modules, I came up with the below setup.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Use Case&lt;a href="https://www.skcript.com/svr/building-a-serverless-telegram-chatbot-with-dialogflow-and-firebase-functions/#the-use-case"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;In this article, I'm going to set a simple use case of requesting weather information from the chatbot. And for this, we'll be using the &lt;a href="https://openweathermap.org/"&gt;OpenWeatherMap&lt;/a&gt; API. So in case, you're going to try the same, sign up for it and get yourself an API Key&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the Telegram Bot&lt;a href="https://www.skcript.com/svr/building-a-serverless-telegram-chatbot-with-dialogflow-and-firebase-functions/#creating-the-telegram-bot"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Creating bots in telegram is pretty much fun but there is no fancy UI to do that. All you have to do is just ask another bot to create your bot.&lt;/p&gt;

&lt;p&gt;There is a bot in telegram called &lt;a href="https://t.me/botfather"&gt;Bot Father&lt;/a&gt; and you have to message the bot to create or manage your bots.&lt;/p&gt;

&lt;p&gt;Send &lt;code&gt;/start&lt;/code&gt; to bot father and it will show you the list of the available options.&lt;/p&gt;

&lt;p&gt;Just click on the &lt;code&gt;/newbot&lt;/code&gt; hyperlink and it will automatically send the slash command to create a new bot for you. Following that, you'll be asked for some basic information like Name for the bot, username (remember it should end with "bot").&lt;/p&gt;

&lt;p&gt;On completing, you'll get a token displayed in the final message from bot father. This token is very important so copy it safely somewhere. In the following sections, we'll refer to this token as the telegram bot token or shortly bot token.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up Dialogflow&lt;a href="https://www.skcript.com/svr/building-a-serverless-telegram-chatbot-with-dialogflow-and-firebase-functions/#setting-up-dialogflow"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The user-facing piece is now ready. Let's now focus on the bridge part which is our Dialogflow. Setting up DialogFlow is as simple as setting up the telegram bot. All you've to do is to sign up for Dialogflow and create a new agent.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image5-19.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NZjzMwRX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image5-19.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's it! You're all set with the Dialogflow project. Now, let's go ahead and connect our telegram to the Dialogflow project.&lt;/p&gt;

&lt;p&gt;Navigate to the integration option in the Dialogflow sidebar. This page will list all the possible platforms that Dialogflow can seamlessly integrate. You can navigate to Telegram and enable the platform. This will bring up an option to configure your bot with the help of the bot's token ID - the token that we got from telegram's bot father earlier.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image1-33.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w27IP8kF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image1-33.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Paste the token in the telegram token field of the modal and click on start to complete your operation. As you connect both of these services, you're ready to talk to your bot.&lt;/p&gt;

&lt;p&gt;Click on the bot's link that's available in the last message from bot father to start the bot. Now, all you can send is just "Hi" and a few other basic greetings. This is because Dialogflow comes with basic greetings inbuilt and for anything more you need to configure it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up the Weather intents&lt;a href="https://www.skcript.com/svr/building-a-serverless-telegram-chatbot-with-dialogflow-and-firebase-functions/#setting-up-the-weather-intents"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Let's make the bot more meaningful by making it understand what we're trying to ask. To do that we need to create something called Intents in Dialogflow (This is quite a common term used in chatbot domain). Intents are nothing but conversations that happen between the bot and the user. In our case, we're going to ask the bot to give us the weather information, so let's create an Intent called "AskWeather".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image3-22.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qmvwjL-I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image3-22.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The real magic happens when we configure the training phrase.&lt;/p&gt;

&lt;p&gt;The training phrases are nothing but the statements that the user asks or tells the bot in the conversation. In our cases, the phrases could be any of the following for weather information&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"What's the weather in Dubai?"
"What's the weather in Dubai tomorrow?"

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Also, if you notice there is certain information hidden inside these statements, which is nothing but the city of which we're asking the weather for and the time or date. Dialogflow is smart enough to identify these in our conversation and extract them as variables. In case, if the bot is missing it we can also configure ourselves by just selecting and mapping it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image10-4.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2KfTGyYt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image10-4.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On scrolling down, you can see "Action and Parameters" which is where we define the properties required and action mapped to this specific intent.&lt;/p&gt;

&lt;p&gt;Actions in Dialogflow intents are nothing more than a namespace that we give to the action performed in webhook, as a result of this intent to get data from your customer services.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image11-3.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zmMbqLwQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image11-3.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In our case, the city and date are the possible params, but it could be more down the line which we can add on the fly. Also, I've made the city parameter as required field as we won't be able to get the weather information without a city or location. But, the date is optional since we can assume that the user is asking for today's weather, in case if it is not mentioned implicitly.&lt;/p&gt;

&lt;p&gt;Now, that we've configured the intent, we can start testing it. Before that, save the intent and then the system will take some time to retrain the agent. So once it's trained, you can try asking the bot in the interface to the right side.&lt;/p&gt;

&lt;p&gt;In the right section, after asking your question the DF system will parse the statement and show you the action and parameter for the corresponding user phrases.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image2-32.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0urZvvfB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image2-32.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up Cloud Functions&lt;a href="https://www.skcript.com/svr/building-a-serverless-telegram-chatbot-with-dialogflow-and-firebase-functions/#setting-up-cloud-functions"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The dialogs are set now! Time for the geeky stuff. Not every dialog can be answered with some static reply or a bunch of static questions. This is where the webhook/fulfilments come into the place where we can configure intents to be handled by your server. In our case, as our title says we're going to use firebase cloud functions as our backend.&lt;/p&gt;

&lt;p&gt;Let's get started by creating our new firebase project in our local system. In this article, I'm going to use an existing firebase project.&lt;/p&gt;

&lt;p&gt;Setting up the local project&lt;/p&gt;

&lt;p&gt;Create a new folder in a location in your machine and initialize a firebase project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g firebase-tools
mkdir WeatherKiosk
cd WeatherKiosk
firebase init

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The initializer will be a wizard which asks you the project and the modules we need for the project. I'll be selecting the project and the functions as the module.&lt;/p&gt;

&lt;p&gt;On completion, you'll be finding a functions folder where we have the server code. Let's write an endpoint for Dialogflow to use as webhook/fulfillment.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;functions/index.js&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const functions = require("firebase-functions");

exports.chatWebhook = functions.https.onRequest((request, response) =&amp;gt; {
  response.json({
    fulfillmentMessages: [
      {
        text: {
          text: ["Text response from webhook"],
        },
      },
    ],
  });
});

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, this endpoint will send back a simple text response. For now, I'm having this as a dummy text response. In the later stages, we'll configure the weather API for getting the expected weather data.&lt;/p&gt;

&lt;p&gt;Let's take it to live by deploying the functions with the below code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;firebase deploy --only functions

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After deploying you can get the endpoint from the firebase function's console. Copy the URL, this will be our Webhook's URL in DF.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image7-9.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MbNJ-ZYL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image7-9.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Configuring the fulfillment in Dialogflow&lt;/p&gt;

&lt;p&gt;In the sidebar of the Dialogflow agent, you'll find the fulfillment section where you need to configure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image9-4.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xmwiPJOl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image9-4.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Post that you can configure the intent to use the fulfillment like below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image8-5.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Be9F844b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image8-5.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's check if it works by sending a message to the bot. The bot has to reply "Text response from webhook" then we can confirm that it works.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image6-10.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rQzG5PvW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image6-10.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Final Code with API Integration&lt;a href="https://www.skcript.com/svr/building-a-serverless-telegram-chatbot-with-dialogflow-and-firebase-functions/#the-final-code-with-api-integration"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;I've updated the function to parse the params and actions and make the corresponding call to Weather API, and generate the text response that will be sent to the user as bot's reply.&lt;/p&gt;

&lt;p&gt;function/index.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const functions = require("firebase-functions");
const Axios = require("axios");

const WEATHER_API_KEY = "YOUR OPENWEATHERMAP HERE";

const responseBuilder = (msg) =&amp;gt; ({
  fulfillmentMessages: [{ text: { text: [msg] } }],
});

exports.chatWebhook = functions.https.onRequest((req, res) =&amp;gt; {
  let body = req.body;
  let { parameters, action } = body.queryResult;

  if (action !== "askWeather") return res.json(responseBuilder("Unable to process your query"));
  let city = parameters["geo-city"];
  let url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&amp;amp;appid=${WEATHER_API_KEY}`;

  return Axios.post(url)
    .then((result) =&amp;gt; result.data)
    .then((data) =&amp;gt; `The temperature is  ${Math.round(data.main.temp - 273.15)} °C`)
    .then((message) =&amp;gt; res.json(responseBuilder(message)))
    .catch((err) =&amp;gt; res.json(responseBuilder(err.message)));
});

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the above code, we're extracting the action and the parameters from the body which is sent by Dialogflow when the user asks the question.&lt;/p&gt;

&lt;p&gt;After deploying the function, the bot will be able to process the user's message with the help of the webhook.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image4-23.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Co5y6ln4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image4-23.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is just a very small example of what Dialogflow can do, but you can do a lot more with it. It also provides some custom formatting for telegram like inline buttons, links, etc.&lt;/p&gt;

</description>
      <category>firebase</category>
      <category>dialogflow</category>
      <category>chatbots</category>
      <category>telegrambot</category>
    </item>
    <item>
      <title>Extract UI Components with AlpineJS and TailwindCSS using x-spread and @apply</title>
      <dc:creator>Praveen Juge</dc:creator>
      <pubDate>Thu, 06 Aug 2020 14:41:20 +0000</pubDate>
      <link>https://forem.com/skcript/extract-ui-components-with-alpinejs-and-tailwindcss-using-x-spread-and-apply-36fg</link>
      <guid>https://forem.com/skcript/extract-ui-components-with-alpinejs-and-tailwindcss-using-x-spread-and-apply-36fg</guid>
      <description>&lt;p&gt;Today we are going to create a dropdown component using &lt;a href="https://github.com/alpinejs/alpine"&gt;AlpineJS&lt;/a&gt; and &lt;a href="https://tailwindcss.com/"&gt;TailwindCSS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;AlpineJS is a simple JavaScript toolkit for creating reactive components. TailwindCSS is an utility based CSS framework. You can use both these frameworks in the HTML markup itself. But for some repeating components, you can extract it as a separate component so that you can reuse it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The following example doesn't follow accessibility principles to keep it simple. Make sure you follow accessibility principles for production websites.&lt;/p&gt;

&lt;p&gt;Check out this &lt;a href="https://gist.github.com/praveenjuge/1ee034f3a5c493141e73e7183b1de33c"&gt;gist&lt;/a&gt; for full source code.&lt;/p&gt;

&lt;h2&gt;
  
  
  HTML
&lt;/h2&gt;

&lt;p&gt;Open a new html file in your website and add the following snippet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"dropdown"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"dropdown-trigger"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"open-color-menu"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    Open Dropdown
  &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"dropdown-list"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"color-menu"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"dropdown-item"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Red&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"dropdown-item"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Blue&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"dropdown-item"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Green&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  CSS
&lt;/h2&gt;

&lt;p&gt;Let's start with all the CSS that we need, I assume you have already set up a Tailwind integrated website. So in your CSS file, you can add this.&lt;/p&gt;

&lt;p&gt;We use a special &lt;a href="https://tailwindcss.com/docs/functions-and-directives/#apply"&gt;@apply&lt;/a&gt; function here that is available from TailwindCSS. It's used to inline any Tailwind utility classes into our own custom CSS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;x-cloak&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;@apply&lt;/span&gt; &lt;span class="err"&gt;hidden;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.dropdown-trigger&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;@apply&lt;/span&gt; &lt;span class="err"&gt;inline-block&lt;/span&gt; &lt;span class="err"&gt;py-2&lt;/span&gt; &lt;span class="err"&gt;px-4&lt;/span&gt; &lt;span class="err"&gt;rounded-md&lt;/span&gt; &lt;span class="err"&gt;bg-purple-700&lt;/span&gt; &lt;span class="err"&gt;text-white;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.dropdown-list&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;@apply&lt;/span&gt; &lt;span class="err"&gt;absolute&lt;/span&gt; &lt;span class="err"&gt;z-10&lt;/span&gt; &lt;span class="err"&gt;shadow-md&lt;/span&gt; &lt;span class="err"&gt;w-56&lt;/span&gt; &lt;span class="err"&gt;flex&lt;/span&gt; &lt;span class="err"&gt;flex-col&lt;/span&gt; &lt;span class="err"&gt;border&lt;/span&gt; &lt;span class="err"&gt;border-solid&lt;/span&gt; &lt;span class="err"&gt;border-gray-200&lt;/span&gt; &lt;span class="err"&gt;bg-white&lt;/span&gt; &lt;span class="err"&gt;p-2&lt;/span&gt; &lt;span class="err"&gt;rounded;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.dropdown-item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;@apply&lt;/span&gt; &lt;span class="err"&gt;relative&lt;/span&gt; &lt;span class="err"&gt;flex&lt;/span&gt; &lt;span class="err"&gt;px-2&lt;/span&gt; &lt;span class="err"&gt;py-1&lt;/span&gt; &lt;span class="err"&gt;items-center&lt;/span&gt; &lt;span class="err"&gt;text-gray-800;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Vo7oFwXA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image1-31.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Vo7oFwXA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image1-31.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  JS
&lt;/h2&gt;

&lt;p&gt;Next, we can use Alpine to give our dropdown that sweet interactivity. Make sure you already have AlpineJS defined and then change your dropdown markup to this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;x-data=&lt;/span&gt;&lt;span class="s"&gt;"dropdown()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"dropdown-trigger"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"open-color-menu"&lt;/span&gt; &lt;span class="na"&gt;x-spread=&lt;/span&gt;&lt;span class="s"&gt;"trigger"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    Open Dropdown
  &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"dropdown-list"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"color-menu"&lt;/span&gt; &lt;span class="na"&gt;x-spread=&lt;/span&gt;&lt;span class="s"&gt;"dropdown"&lt;/span&gt; &lt;span class="na"&gt;x-cloak&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"dropdown-item"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Red&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"dropdown-item"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Blue&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"dropdown-item"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Green&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;x-data&lt;/code&gt; is the encapsulating function, the &lt;code&gt;x-spread&lt;/code&gt; attributes will allow us to bind the object of Alpine directives to an this element so that we can reuse it everywhere.&lt;/p&gt;

&lt;p&gt;And &lt;code&gt;x-cloak&lt;/code&gt; hides the dropdown list before Alpine is defined. So we won't see the dropdown list and then hide on page load.&lt;/p&gt;

&lt;p&gt;And then add this to a script file in your website:&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dropdown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;open&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;trigger&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@keydown.escape&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@click&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;dropdown&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@keydown.escape&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x-show.transition&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="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;open&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@click.away&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you click on the dropdown trigger,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;@click&lt;/code&gt; directive makes the &lt;code&gt;open&lt;/code&gt; variable true.&lt;/li&gt;
&lt;li&gt;When the open variable is true, the dropdown will show because of the &lt;code&gt;x-show.transition&lt;/code&gt; directive, where &lt;code&gt;transition&lt;/code&gt; will add a little animation while opening up.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you click outside or press escape button,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;@click.away&lt;/code&gt; and &lt;code&gt;@keydown.escape&lt;/code&gt; directives will make the &lt;code&gt;open&lt;/code&gt; variable false.&lt;/li&gt;
&lt;li&gt;It will make the same &lt;code&gt;x-show.transition&lt;/code&gt; hide the dropdown element.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BLOdaCh3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.skcript.com/svrmedia/heroes/image2-1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BLOdaCh3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.skcript.com/svrmedia/heroes/image2-1.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;And that's it, you can use this markup everywhere in your website and it will work for you. If you need to change CSS or JS in this component, you have to do it just once.&lt;/p&gt;

&lt;p&gt;Check out this &lt;a href="https://gist.github.com/praveenjuge/1ee034f3a5c493141e73e7183b1de33c"&gt;gist&lt;/a&gt; for the full source code.&lt;/p&gt;

</description>
      <category>tailwindcss</category>
      <category>alpinejs</category>
      <category>css</category>
    </item>
    <item>
      <title>Web Animation With GSAP</title>
      <dc:creator>Sooraj (PS)</dc:creator>
      <pubDate>Wed, 05 Aug 2020 02:47:25 +0000</pubDate>
      <link>https://forem.com/skcript/web-animation-with-gsap-12o6</link>
      <guid>https://forem.com/skcript/web-animation-with-gsap-12o6</guid>
      <description>&lt;p&gt;Ah animations, who doesn’t love some animations! When I was young, I was so curious to know how my favorite cartoons were animated. I used to imagine all sorts of tricks they would have used - maybe it was black magic?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage1-1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage1-1.gif" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Me getting excited for an animated series (back then … and now)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As I grew up, I realised animations were nothing but static frames which were slightly different from each other but when viewed so quickly in sequence seemed to “animate”. In earlier days animation was very difficult and blocky on the web with the technological limitations of that era. Nowadays, with high performance devices and with almost no tech limitations, it's possible to animate anything on the web with ease. But we still look out for ways which are easy, lightweight, high performant and but that can still deliver what all the other heavyweight packages offer right?&lt;/p&gt;

&lt;p&gt;Well that’s when I found this plugin/package/library called &lt;strong&gt;GSAP&lt;/strong&gt;. GSAP is an industry standard animation library that was created by GreenSock. It uses highly optimized and high performance javascript animation with a small bundle size. In this article, I will take you through the steps of setting up and writing cool animations on the web using GSAP.&lt;/p&gt;

&lt;p&gt;I came across GSAP last year while I was browsing through animation tutorials. But back then I was not able to quite grasp its concepts. So last month I spent a couple of days exploring GSAP and immediately my mind was blown.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fas.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fas.gif" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;My Brain, after using GSAP&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And since the release of GSAP3, all the functions of GSAP are very easy to both code and understand. We will be using GSAP version 3 for this article. We will be going through&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;gsap.to()&lt;/li&gt;
&lt;li&gt;gsap.from()&lt;/li&gt;
&lt;li&gt;gsap.fromTo()&lt;/li&gt;
&lt;li&gt;gsap.timeline()&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First of all let us set up our codebase. To install GSAP for your project, just go to your project directory and use the cli command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;gsap
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you need to use the CDN version, you can just head over to &lt;a href="https://greensock.com/" rel="noopener noreferrer"&gt;https://greensock.com/&lt;/a&gt; and Click on “&lt;strong&gt;Get GSAP Now”&lt;/strong&gt; button, and copy and paste the min.js link to your code’s html file.&lt;/p&gt;

&lt;p&gt;In this article we will be using the CDN version and along with it Codepen as our code editor and Bootstrap 4 for design. Now that our setup is done, nice and easy. Let us start with GSAP and its functions.&lt;/p&gt;

&lt;p&gt;Now if you are a web developer, in the beginning you would have spent countless hours animating the color of a DIV or moving a DIV across the screen using CSS &lt;strong&gt;animations&lt;/strong&gt; and &lt;strong&gt;transitions&lt;/strong&gt;. If you are good at JavaScript, GSAP will make animations a piece of cake. And the best part is that you don’t have to manually write any CSS animations. You only need to specify what property to animate and gsap will do that for you.&lt;/p&gt;

&lt;p&gt;The way GSAP makes smooth and performant efficient animations is through a method called &lt;strong&gt;requestAnimationFrame&lt;/strong&gt;. Now this is a browser function that optimises itself on each browser and does not execute when we are not on the viewport. So it's completely efficient.&lt;/p&gt;

&lt;p&gt;Now to the smoothness. Let’s assume we want to make an element disappear by changing its opacity from 1 to 0. When you run this in CSS, we will see the element disappear in the blink of an eye. That is because there are no frames in between 1 and 0. There is a common term in animation called “&lt;strong&gt;tweening&lt;/strong&gt;”, which means adding intermediate frames between the start and end, to make the transition as smooth as possible. gsap takes care of this and we only need to decide the duration and the ease (ease is the property that defines how the animation will happen over time. We will get to this later in the article). Now let us start with the methods.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. gsap.to()&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;to() is a method provided by gsap to animate any element to the new state. to() method takes 2 arguments. So it takes your original element’s styles &lt;strong&gt;“to”&lt;/strong&gt; the new style properties provided in the vars. For example,&lt;/p&gt;

&lt;p&gt;original properties -&amp;gt; tween -&amp;gt; { opacity: 0 }&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;gsap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DOMelement&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;vars&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first argument is an element. You can pass either a DOM element or selector string to target an element. The second argument is something called “&lt;em&gt;vars&lt;/em&gt;”, which is just an object that has all properties that you want to change. vars mostly consists of all the CSS properties that can be animated, but follow a camelCase syntax. For example “z-index” must be given as “zIndex”.&lt;/p&gt;

&lt;p&gt;A simple example is to move an element’s x position to a new position (or left).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fe9d5lxr9nhsg2m2teci7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fe9d5lxr9nhsg2m2teci7.gif" alt="Alt Text" width="600" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. gsap.from()&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;from() is a similar method provided by gsap to animate any element from a new state. to() method takes 2 arguments. This first adds the styles given in the vars and theme gradually brings it to the original styles of the element. For example,&lt;/p&gt;

&lt;p&gt;{ opacity: 0 } -&amp;gt; tween -&amp;gt; original properties&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;gsap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DOMelement&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;vars&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The argument structure is the same as to() method.&lt;/p&gt;

&lt;p&gt;A simple example is to move an element’s x position from a position ( or left ).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzk0466x5s8i4ph93zz6w.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzk0466x5s8i4ph93zz6w.gif" alt="Alt Text" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. gsap.fromTo()&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;fromTo() is a method provided by gsap to animate any element from a given state to the new state. fromTo() method takes 3 arguments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;gsap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DOMelement&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;varsFrom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;varsTo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first argument is an element. The second argument is the properties that will be applied first to the element. The third argument is the properties that it will be reaching to at the end. For example,&lt;/p&gt;

&lt;p&gt;{ opacity: 0 } -&amp;gt; tween -&amp;gt; { opacity: 1 }&lt;/p&gt;

&lt;p&gt;A simple example is to move an element’s x position from a position ( or left ) to a new position.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fibd5k0fhfjoetk4sxryx.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fibd5k0fhfjoetk4sxryx.gif" alt="Alt Text" width="600" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. gsap.timeline()&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;timeline() is a method provided by gsap to create a sequential timeline for animation. Suppose you need to animate 5 elements. And each element’s animation needs to wait for the previous animation to complete. This case becomes very complex in keyframe animations, because maintenance becomes a major issue. That is where timeline() method comes into use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;myTimeline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gsap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timeline&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;myTimeline&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DOMelement&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;vars&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DOMelement&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;vars&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DOMelement&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;varsFrom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;varsTo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;timeline() does not take any argument. You can add as many animations to a timeline. Each animation is triggered only after its previous animation has been completed.&lt;/p&gt;

&lt;p&gt;Timeline animation is a bit different from the other animations.&lt;/p&gt;

&lt;p&gt;Each method also has specific callbacks that you can use to execute certain functions after an update. Be sure to check out the callback functions on the gsap documentation, because you might never know what will miss.&lt;/p&gt;

&lt;p&gt;And it is also very easy to integrate gsap methods with Promises, because these methods also return a promise on execution. This would be very useful when fetching data from an api. For example, If you have a list of books, and you add a book. The API/hook to add a new book will in turn set a loading and add the new book to the data and return a promise. You can now set the GSAP method in the promise resolving step and once the animation is done, the promise returned from that can be used to reset the loading. Promises in GSAP can also be used instead of timelines for shorter animation chains.&lt;/p&gt;

&lt;p&gt;Apart from these &lt;strong&gt;gsap methods&lt;/strong&gt;, there are a whole lot of plugins, some of which are free and some need a premium account. Some of the other plugins are &lt;strong&gt;ScrollTrigger, SnapPlugin, MotionPath, Inertia, Pixi, Text&lt;/strong&gt; etc.&lt;/p&gt;

&lt;p&gt;You can use the &lt;strong&gt;gsap&lt;/strong&gt; methods in any way, and in any order to your creativity level. I have just made a simple button click animation. Even though it is minimal, it is effective&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5ao6o92ci4xlenziypre.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5ao6o92ci4xlenziypre.gif" alt="Alt Text" width="600" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The main thing to remember is that, although animations are really eye catching to the user, overdoing it will definitely be a disadvantage. Don’t be flashy. Try to keep animations minimal but also attractive at the same time.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>animation</category>
      <category>css</category>
    </item>
    <item>
      <title>Indexing Firebase Data in Algolia For Full-Text Search</title>
      <dc:creator>Varun Raj</dc:creator>
      <pubDate>Sat, 01 Aug 2020 12:29:37 +0000</pubDate>
      <link>https://forem.com/skcript/indexing-firebase-data-in-algolia-for-full-text-search-1fkg</link>
      <guid>https://forem.com/skcript/indexing-firebase-data-in-algolia-for-full-text-search-1fkg</guid>
      <description>&lt;p&gt;Firebase being a BaaS solution comes with a bunch of features for developers to build their app faster and with real-time capabilities. But, there is one thing that is yet to be addressed by Firebase’s feature set - the ability to perform full-text search on the data that is stored in Firebase databases (like Firestore or Realtime Database). This creates a huge bottleneck for developers since search is one of the primary user experiences for any application we build.&lt;/p&gt;

&lt;p&gt;Thankfully we’ve got Algolia that can help us solve this problem. This is a service which helps you store the index of data from firebase, making it searchable. The important advantage of Algolia is that it’s supported in different platforms with a lot of UI components, which can be easily used to develop search modules for your apps.&lt;/p&gt;

&lt;p&gt;In this article, I’ll walk you through how to set up your Algolia and index your data when new data is created or modified in your Firebase Firestore. This article is split into the following sections, you can skip any, in case if you’re already aware of them.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Creating an account in Algolia&lt;/li&gt;
&lt;li&gt; Setting up Firebase Cloud Function&lt;/li&gt;
&lt;li&gt; Index data from Firebase Firestore on create and edit.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Creating an account in Algolia#
&lt;/h3&gt;

&lt;p&gt;As the first step, you can navigate to Algolia and register your account by either signing up with Google or Github or just with email.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image6-9.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bZ2RC-et--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image6-9.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you’ve created your Algolia account, go to the dashboard and find a default project created under your account. Let’s use that project for this article.&lt;/p&gt;

&lt;p&gt;Similar to Firestore collections Algolia has an “Index” - the aggregation of data under a common umbrella. Create your index to store the data.&lt;/p&gt;

&lt;p&gt;In this case, I have created an index called “Recipes” to save food recipes&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image1-30.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BSur81pK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image1-30.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After creating an account, add data to the index. Among the 3 different options for adding the data, we’ll be using the API for importing data with help from the firebase cloud functions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image4-22.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Xa-TE9cD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image4-22.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up Firebase Cloud Functions#
&lt;/h3&gt;

&lt;p&gt;Let’s assume that you’re already having a firebase project and upgraded to &lt;strong&gt;Blaze Plan&lt;/strong&gt; since we have to call external APIs from functions. Then, initialize the functions in your project with the Firebase CLI tool and setup cloud functions.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ProjectFolder
firebase init 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On completion, you’ll find a folder named “&lt;strong&gt;functions&lt;/strong&gt;” in your project folder. Open the project folder in a text editor like VSCode.&lt;/p&gt;

&lt;p&gt;Now we’re going to index data in the “recipes” collection to our new Algolia index. So, let’s create two functions that listen to onCreate and onEdit of any document in the “recipes” collection.&lt;/p&gt;

&lt;p&gt;functions/index.js&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const functions = require('firebase-functions');
const onCreate = require('./triggers/recipes/onCreate');
const onEdit = require('./triggers/recipes/onEdit');

exports.onRecipeCreate = functions.firestore
                                   .document("recipes/{recipeId}")
                                   .onCreate(onCreate);

exports.onRecipeEdit = functions.firestore
                                   .document("recipes/{recipeId}")
                                   .onUpdate(onEdit);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Create the handler functions for onCreate of recipe docs and onEdit of the same. So, I’ve created two files under the triggers folder of our functions&lt;/p&gt;

&lt;p&gt;&lt;em&gt;functions/triggers/recipes/onCreate.js&lt;/em&gt;&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = (snap, context) =&amp;gt; {
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;functions/triggers/recipes/onEdit.js&lt;/em&gt;&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = (change, context) =&amp;gt; {
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Index data from Firebase Firestore on create and update.#
&lt;/h3&gt;

&lt;p&gt;To index the documents in Algolia, configure Algolia keys in the firebase cloud functions. The secured way is to use firebase environment variables.&lt;/p&gt;

&lt;p&gt;To get the API keys from Algolia, go API Keys section in Algolia dashboard and copy your Application ID and the Admin API Key&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image5-18.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LEC0k1-K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image5-18.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These keys need to be configured to our Firebase Cloud function’s environment variables. You can do that with the help of the firebase CLI tool&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;firebase functions:config:set algolia.app_id="THE APP ID" algolia.admin_key="THE ADMIN API KEY" 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After updating the config, we can start using it in the ‘functions’ code. In order to use Algolia, we need to install the npm package in our functions code base.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd functions
npm install --save algoliasearch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After installing the package, create a config file to setup Algolia with the API Keys&lt;/p&gt;

&lt;p&gt;&lt;em&gt;functions/config/algolia.js&lt;/em&gt;&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const functions = require('firebase-functions');
const algoliasearch = require('algoliasearch');

const ALGOLIA_ID = functions.config().algolia.app_id;
const ALGOLIA_ADMIN_KEY = functions.config().algolia.admin_key;

module.exports = algoliasearch(ALGOLIA_ID, ALGOLIA_ADMIN_KEY);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This file exports the Algolia Client which we can use to index data and delete the indexed data. Thus, we need to import this in our onCreate and onEdit file.&lt;/p&gt;

&lt;p&gt;With the client, you can initialize the index, in our case “Recipes” and we use &lt;code&gt;saveObject&lt;/code&gt; function to store the data inside the index.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;functions/triggers/recipes/onCreate.js&lt;/em&gt;&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const client = require("../../config/algolia");
const recipeIndex = client.initIndex('Recipes');

module.exports = (snap, context) =&amp;gt; {
 let data = snap.data();
 data.objectID = snap.id;
 recipeIndex.saveObject(data);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;functions/triggers/recipes/onEdit.js&lt;/em&gt;&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const client = require("../../config/algolia");
const recipeIndex = client.initIndex('Recipes');

module.exports = (change, context) =&amp;gt; {
 let data = change.after.data();
 data.objectID = change.after.id;
 recipeIndex.saveObject(data);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the above two files, we’ve extracted the data from the snap (in onCreate) and changed (in onEdit) to a variable called data. In Algolia, the primary key is stored in the attribute &lt;code&gt;objectID&lt;/code&gt; of data, so we’re storing the firebase document ID as the objectID.&lt;/p&gt;

&lt;p&gt;Let’s deploy the function and test the setup. Deploy the firebase functions by executing the below command from the project’s root folder.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;firebase deploy --only functions
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After deploying, create a document under the **recipes **collection and see if it’s indexed in Algolia.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image2-31.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ewbyHcBh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image2-31.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As soon as you create the data in Firestore, the cloud functions will be triggered and the indexes will be created in your Algolia project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svrmedia/heroes/image3-21.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PaiK0pa8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.skcript.com/svrmedia/heroes/image3-21.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Similarly, the index will be updated every time you edit the data in Firestore. This happens in realtime and thus your search will be always updated.&lt;/p&gt;

&lt;p&gt;Thus, you can replicate the data from firebase to Algolia to create a full-text search index. Hope this article helped you to get started with Algolia setup for your firebase project.&lt;/p&gt;

</description>
      <category>firebase</category>
      <category>algolia</category>
      <category>search</category>
    </item>
    <item>
      <title>Rise of Tailwind - A Utility-First CSS Framework</title>
      <dc:creator>Praveen Juge</dc:creator>
      <pubDate>Fri, 24 Jul 2020 04:21:23 +0000</pubDate>
      <link>https://forem.com/skcript/rise-of-tailwind-a-utility-first-css-framework-24di</link>
      <guid>https://forem.com/skcript/rise-of-tailwind-a-utility-first-css-framework-24di</guid>
      <description>&lt;p&gt;Tailwind is a utility-first CSS framework, the keyword being ‘utility’. It is basically a set of classes that you can use in your HTML.&lt;/p&gt;

&lt;p&gt;For instance, to recreate the following button, we can use:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage6-8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage6-8.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"bg-purple-700 text-white py-1 px-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Button&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here the classes are prebuilt by tailwind to give the following CSS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.bg-purple-700&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#6b46c1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.text-white&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#ffffff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.py-1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.25rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.25rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.px-4&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="nl"&gt;padding-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&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;Therefore, we don't have to write any custom CSS to get this button. This can be heavily extended to build whole web applications without the need for any other styles apart from a tailwind.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of Tailwind that I love
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No need to write any responsive media queries any more&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want something to display on mobile and not on the desktop, add the class &lt;code&gt;block md:hidden&lt;/code&gt;. As this is a mobile-first approach, that element will have &lt;code&gt;display: block&lt;/code&gt; on mobile and after the &lt;code&gt;md&lt;/code&gt; breakpoint, which is &lt;code&gt;768px&lt;/code&gt;, it will toggle to &lt;code&gt;display: none&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Consistent spacing and typography&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As everything in utility classes is predefined, we will have consistent padding and margin throughout our platform. And, typography in tailwind is the best, you don't have the need to change any of the default config yet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage5-17.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage5-17.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PurgeCSS built-in&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It has the ability to remove unused CSS that we didn't use in our app. It does this with the help of &lt;a href="https://purgecss.com/" rel="noopener noreferrer"&gt;purge css&lt;/a&gt; built-in within tailwind. This gives loads of size savings on the final CSS build.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's build something...
&lt;/h2&gt;

&lt;p&gt;Now let's build a simple alert component to see how tailwind works in detail. Enter the following command in your terminal, make sure you have &lt;a href="https://nodejs.org/" rel="noopener noreferrer"&gt;Node&lt;/a&gt; installed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;tailwind-alert
&lt;span class="nb"&gt;cd &lt;/span&gt;tailwind-alert
npm init &lt;span class="c"&gt;# Follow the steps to initialize a npm project&lt;/span&gt;
&lt;span class="nb"&gt;touch &lt;/span&gt;index.html postcss.config.js main.css
npm i &lt;span class="nt"&gt;-save&lt;/span&gt; tailwindcss postcss-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your &lt;code&gt;index.html&lt;/code&gt;, &lt;code&gt;postcss.config.js&lt;/code&gt; and &lt;code&gt;main.css&lt;/code&gt; copy the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- index.html --&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"tailwind.css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"m-10"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"alert"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;I'm an alert that informs you of stuff.&lt;span class="nt"&gt;&amp;lt;/div&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// postcss.config.js&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tailwindcss&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* main.css */&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;utilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, add the following script in your &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// package.json&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scripts&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;start&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="s2"&gt;postcss main.css -o tailwind.css --watch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now do &lt;code&gt;npm start&lt;/code&gt; in your terminal and open &lt;code&gt;index.html&lt;/code&gt; in your browser, you should see this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage3-20.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage3-20.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Style with tailwind&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's style it with a tailwind! For a typical alert component, we need to give a background color and text color first. So in your &lt;code&gt;index.html&lt;/code&gt;, change the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"bg-purple-200 text-purple-700"&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"alert"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;I'm an alert that informs you of stuff.&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage1-28.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage1-28.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let's add some padding with rounded corners, for padding we have &lt;code&gt;p-{n}&lt;/code&gt; utilities and &lt;a href="https://tailwindcss.com/docs/border-radius/" rel="noopener noreferrer"&gt;border radius&lt;/a&gt; can be also given with utility classes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"bg-purple-200 text-purple-700 py-2 px-4 rounded"&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"alert"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;I'm an alert that informs you of stuff.&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage2-29.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage2-29.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This looks better! But, for reusability, we can make this a component. In your &lt;code&gt;main.css&lt;/code&gt; file add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* main.css */&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;.alert&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;@apply&lt;/span&gt; &lt;span class="err"&gt;border-2&lt;/span&gt; &lt;span class="err"&gt;border-solid&lt;/span&gt; &lt;span class="err"&gt;text-base&lt;/span&gt; &lt;span class="err"&gt;rounded&lt;/span&gt; &lt;span class="err"&gt;py-2&lt;/span&gt; &lt;span class="err"&gt;px-4;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.alert-primary&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;@apply&lt;/span&gt; &lt;span class="err"&gt;bg-purple-200&lt;/span&gt; &lt;span class="err"&gt;border-purple-200&lt;/span&gt; &lt;span class="err"&gt;text-purple-700;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;utilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;@apply&lt;/code&gt; is a special tailwind directive that makes it easy to refer to the tailwind utility classes here. Now refresh &lt;code&gt;index.html&lt;/code&gt; in your browser and you will see this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage4-21.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.skcript.com%2Fsvrmedia%2Fheroes%2Fimage4-21.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can now use this alert component everywhere and can change its styles in one place. Since we are using tailwind classes, this will give us better control of spacing, colors and typography compared to our own CSS styles.&lt;/p&gt;

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

&lt;p&gt;As I am using tailwind in my projects, I didn't have the need to use sass or even create multiple stylesheets. Everything I need can be done within the tailwind itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Some cons that I see:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The steep learning curve for new developers&lt;/li&gt;
&lt;li&gt;Postcss takes a long time to compile for big projects&lt;/li&gt;
&lt;li&gt;Initial setup for projects is long&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm sure the tailwind team will address and solve these issues with the best they can in the future. Check out the &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt; and get started. Happy coding!&lt;/p&gt;

</description>
      <category>tailwindcss</category>
      <category>css</category>
    </item>
    <item>
      <title>What I learnt about obsessing with my competitors</title>
      <dc:creator>Karthik Kamalakannan</dc:creator>
      <pubDate>Sat, 16 Feb 2019 15:50:51 +0000</pubDate>
      <link>https://forem.com/skcript/what-i-learnt-about-obsessing-with-my-competitors-5dif</link>
      <guid>https://forem.com/skcript/what-i-learnt-about-obsessing-with-my-competitors-5dif</guid>
      <description>&lt;p&gt;I am obsessed with my competitors. I literally track them everywhere. Meticulously and relentlessly.&lt;/p&gt;

&lt;p&gt;When I started &lt;a href="https://www.skcript.com"&gt;Skcript&lt;/a&gt; back in 2013, I was obsessed over my competition that I would give a lot of damn about it. Few years went by, and it was 2016, and the feeling of never being able to ‘pause’ (not stop) my running started sinking in. I went on a drive one nice evening to see how I cloud overcome this mindset and move on to focus on other things that we could do at Skcript.&lt;/p&gt;

&lt;p&gt;What I realized about analyzing by competition was something different.&lt;/p&gt;

&lt;p&gt;People say that competition is good. And that you will have to be obsessed over your competition. The real reason behind that is not to keep your company updated all the time, but to know what your customers really want. Period. It is that simple.&lt;/p&gt;

&lt;p&gt;Knowing what your customer wants is more important than watching your competition closely. It is probably the only single metric that will matter to you when you are new to the market trying to create something good.&lt;/p&gt;

&lt;p&gt;Watching your competition and being obsessed over them comes as a part of knowing your customers well enough.&lt;/p&gt;

&lt;p&gt;Post that long drive I had in 2016, after being stressed, the one thing that changed in me to build great products that matter, is where I looked at my competition.&lt;/p&gt;

&lt;p&gt;Earlier, I used to obsessively follow them everywhere. On social media, get more information about them from friends, and my major stress came in when I used to hear news saying that they on-boarded say 2000 more users on-to their platform.&lt;/p&gt;

&lt;p&gt;Today, all that I look for and the one metric that helped me grow our revenue was to analyze my competitors’ feature set and figure out why they built it like they did. Considering my competitor as one of my biggest and free user-testing providers made all the difference.&lt;/p&gt;

&lt;p&gt;Ultimately, we all are here to solve a customers’ problems. Not our own problems.&lt;/p&gt;




&lt;p&gt;This post first appeared on &lt;a href="https://www.skcript.com/karthik/about-watching-competition/"&gt;Karthik's Desk on Skcript&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>startup</category>
      <category>competition</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Writing your first Business Model in Hyperledger Composer</title>
      <dc:creator>Naveen Honest Raj</dc:creator>
      <pubDate>Wed, 21 Feb 2018 04:53:44 +0000</pubDate>
      <link>https://forem.com/skcript/writing-your-first-business-model-in-hyperledger-composer--4pk0</link>
      <guid>https://forem.com/skcript/writing-your-first-business-model-in-hyperledger-composer--4pk0</guid>
      <description>&lt;p&gt;This article focuses on creating a simple business model that helps you with visualizing the abstract nature of Hyperledger Composer’s language.&lt;/p&gt;

&lt;p&gt;If you are confused on where to start or wasted a lot of your time in getting started with Hyperledger Composer, you should read this article. My co-worker, Varun has explained it in such a simple way that anyone can understand it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Business Network Definition?
&lt;/h2&gt;

&lt;p&gt;The Business Network Definition is the core definition that holds the Hyperledger Composer’s programming model. In short, it controls the model definition, the relationship between them, the access control over them and the actions that could be performed on/with them.&lt;/p&gt;

&lt;p&gt;BND has three core components : &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Model written in .cto files&lt;/li&gt;
&lt;li&gt;The Business Logic written in .js files&lt;/li&gt;
&lt;li&gt;The Access Control Logic written in .acl files&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;(Optional) There is a Query file written in .qry files that help us to query over the persistent DB.&lt;/p&gt;

&lt;p&gt;These three components are easy to maintain and they govern our whole business application on the Composer. &lt;/p&gt;

&lt;p&gt;Let’s see how to write a manageable simple model file that helps anyone understand most of our business logic. We will implement this in the business logic file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding The Key Concepts Of A Model
&lt;/h2&gt;

&lt;p&gt;Before writing our own model, let us understand the key concepts of it. In a model file, you will be defining the following, &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A namespace
namespace org.skcript.svr&lt;/li&gt;
&lt;li&gt;Resources, which includes

&lt;ol&gt;
&lt;li&gt;Participants&lt;/li&gt;
&lt;li&gt;Assets&lt;/li&gt;
&lt;li&gt;Transactions&lt;/li&gt;
&lt;li&gt;Events&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Optional import statements that are used to inherit or import other model files.&lt;/li&gt;

&lt;/ol&gt;

&lt;h2&gt;
  
  
  Resources Are Everything In A CTO File
&lt;/h2&gt;

&lt;p&gt;A ‘Participant’ denotes the person who does the action (in simple terms). This is to whom the ID is issued and this is the one who performs transactions.&lt;/p&gt;

&lt;p&gt;For example: Consider the example&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;participant Author identified by id {
    o Integer id
    o String name
    o String email
    o String specialized_in 
    o Double age
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In the above example, we see there’s a participant named &lt;code&gt;Author&lt;/code&gt; and the keyword &lt;code&gt;identified by&lt;/code&gt; is used to select the primary key. Here, it is &lt;code&gt;id&lt;/code&gt; field that acts as a primary key. We will know the wide applications of having this &lt;code&gt;identified by&lt;/code&gt; on right field to have an easy and readable access to the model.&lt;/p&gt;

&lt;p&gt;The circles are nothing but lower case ‘o’ (The O, yeah ! ).  Composer’s model file has a unique way of representing a new key in their object. But you will get used to it.&lt;/p&gt;

&lt;p&gt;Assets are the resource which our business model has. Considering our above example, &lt;code&gt;Author&lt;/code&gt; is a participant, then &lt;code&gt;Post&lt;/code&gt; will be the asset that he holds. And we know that every post will always belong to an author. There can never be an asset that won’t belong to an author. This can be done by creating a relationship between our participant and asset. This is easy-peasy because of the CTO’s modeling language. &lt;/p&gt;

&lt;p&gt;P.S. You should be careful with relationship because it is unidirectional and you can’t do the vice versa which you can do in most of the application frameworks.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**
* An enumerated type
*/
enum Category {
  o AI
  o BLOCKCHAIN
  o WEB-DEVELOPMENT
  o BACKEND
  o DESIGN
  o FUN
}

/**
 * A post asset.
 */
asset Post identified by id {
  o String id
  o String title
  o Category category
  o DateTime timestamp
  --&amp;gt; Author author
  --&amp;gt; Author coAuthor optional
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In the above example, as we learned earlier &lt;code&gt;identified by&lt;/code&gt; is used with &lt;code&gt;id&lt;/code&gt; as primary key which makes sense. Right? Now you can understand.&lt;/p&gt;

&lt;p&gt;But where’s the new thing coming up? No rush. Let’s take it slow. &lt;br&gt;
Let’s see the &lt;code&gt;Line 21&lt;/code&gt; - we see an arrow. Okay. I didn’t write it because it looks good on the code and it’s not a comment too. That’s again our Composer’s modeling language’s weird way of writing relationship. So we should read it as Post belongs to Author. That’s simple. Done.&lt;br&gt;
In &lt;code&gt;Line 22&lt;/code&gt; , we can see there’s a new keyword &lt;code&gt;optional&lt;/code&gt;. This helps us avoid mandatory entry to create an asset. This is defined as optional by thinking that there may or may not be a coauthor for a particular post.&lt;/p&gt;

&lt;p&gt;Next, why &lt;code&gt;enum&lt;/code&gt; ? It’s for managing a neat code. As our articles goal is not only to learn how to write a model but also to write a good one that can be easy to read and update.&lt;br&gt;
So enum holds the possible values our field can take. So we defined an &lt;code&gt;enum&lt;/code&gt; called &lt;code&gt;Category&lt;/code&gt; and we gave it all the possible values it can take. Now in &lt;code&gt;Line 19&lt;/code&gt; we used it and created a category of &lt;code&gt;enum Category&lt;/code&gt; . &lt;/p&gt;

&lt;p&gt;Transactions are the process in which our participants do the operation on assets. Considering our scenario, author creating a post is also a transaction. &lt;br&gt;
Example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;transaction createPost {
  --&amp;gt; Author owner
  o String title
  o Category category
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The above transaction definition emphasizes that we are creating a post by pointing out the author of the post. We also provide title and category while creating the post.&lt;/p&gt;

&lt;p&gt;P.S: In our next post, we will learn more about the transactions and transaction processor functions. &lt;/p&gt;

&lt;p&gt;Events are used to trigger some other third party application. You can write the logic for the event which will help you to send an email about the author’s new post. These events can be used to help you to send emails if and only if you subscribed to the particular author which helps to avoid spam and improves integrity. Events are also defined the same as transactions. The purpose is only different. Used with &lt;code&gt;event&lt;/code&gt; keyword for declaration.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Endless Possibilities Of The CTO File
&lt;/h2&gt;

&lt;p&gt;You can still segregate the model declaration by &lt;code&gt;abstract&lt;/code&gt;  keyword which won’t create participant or asset in the registry, rather is used to inherit from the other resources.&lt;/p&gt;

&lt;p&gt;Example: Considering the same scenario, try to understand the following code&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;abstract Participant UserInformation identified by name {
  o String name
  o String address
  o String email
  o Integer age
}

participant Author identified by id {
    o Integer id
    o String specialized_in 
    o UserInformation user_information
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We created an &lt;code&gt;abstract&lt;/code&gt; participant which holds most information about a user and we inherit and use that in our &lt;code&gt;Author&lt;/code&gt; participant. This helps us have a clean model that still maintains Single Responsibility Principle. We can do abstract type for assets and transactions too. &lt;/p&gt;

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

&lt;p&gt;There are much more magical things like &lt;code&gt;extends&lt;/code&gt; that we can do with CTO file. But let’s end it clean and easy here. After you write your first model, you will figure out most of the conventions you might need to follow to have a maintainable code. Wish you a good luck, readers.&lt;/p&gt;

</description>
      <category>hyperledger</category>
      <category>composer</category>
      <category>fabric</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>Should I choose Hyperledger Sawtooth 1.0 over Fabric 1.0 for my private blockchain?</title>
      <dc:creator>Karthik Kamalakannan</dc:creator>
      <pubDate>Fri, 16 Feb 2018 17:58:49 +0000</pubDate>
      <link>https://forem.com/skcript/should-i-choose-hyperledger-sawtooth-10-over-fabric-10-for-my-private-blockchain--lhk</link>
      <guid>https://forem.com/skcript/should-i-choose-hyperledger-sawtooth-10-over-fabric-10-for-my-private-blockchain--lhk</guid>
      <description>&lt;p&gt;The Hyperledger Blockchain project is at its peak right now. With big companies like IBM and technology based companies like us, contributing to the project, the project is seeing faster development cycles than it had before. This is something we're definitely proud of.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.skcript.com/svr/what-is-new-in-hyperledger-sawtooth-1-0/"&gt;recently announced Enterprise Ready Sawtooth 1.0&lt;/a&gt; is big. The Sawtooth project, which was moved from Intel to the Linux Foundation, is something that aligns a bit with &lt;a href="https://www.skcript.com/svr/what-is-hyperledger-fabric-and-what-you-should-know-about-it/"&gt;Hyperledger Fabric&lt;/a&gt;, but with a little more maturity.&lt;/p&gt;

&lt;p&gt;The biggest area where both the project differ are in the philosophy behind the projects. &lt;/p&gt;

&lt;p&gt;Hyperledger Sawtooth for example, focuses on creating very secure way to handle your smart contracts, with stricter rules and consensus.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.skcript.com/svr/5-advantages-of-using-hyperledger-fabric-for-your-enterprise-blockchain/"&gt;Hyperledger Fabric&lt;/a&gt; on the other hand, can optionally enforce these rules, which helps a lot of different private blockchain providers right now.&lt;/p&gt;

&lt;p&gt;If you are looking to build a very secure, strictly distributed private blockchain, Sawtooth would be the best choice. Here's why, Sawtooth 1.0 is a major release in the history of Hyperledger Project:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Distributed ledger;&lt;/strong&gt; Sawtooth aims to have distributed ledgers, truly distributed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Secure Smart Contracts;&lt;/strong&gt; With a strict policy to have your information truly distributed, the Smart Contracts are safer and Enterprise ready.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BFT Enabled;&lt;/strong&gt; When I saw that Sawtooth is Enterprise ready, the major reason is that it comes with Byzantine Fault Tolerance features. This BFT feature gives much higher tolerance rate than the Crash Fault Tolerance in Fabric.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Global State Agreement enforces;&lt;/strong&gt; This module gives a assurance that each node has exact same copy of the database as the other notes in the blockchain network. Backed heavily by cryptography.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Parallel Transactions;&lt;/strong&gt; The ability to have parallel transactions with Sawtooth makes all the difference. Thus reducing the amount of time it takes to process transactions in the system.&lt;/p&gt;

&lt;h3&gt;
  
  
  So, should I choose Fabric or Sawtooth?
&lt;/h3&gt;

&lt;p&gt;The decision purely depends on your use-case. A well experienced Blockchain Consultant will be able to help you make this decision faster.&lt;/p&gt;

&lt;p&gt;If you are looking at a private blockchain network that holds highly sensitive data and a sensitive smart contract, Sawtooth could be one option you should consider.&lt;/p&gt;




&lt;p&gt;You can interact in our &lt;a href="https://discourse.skcript.com/c/blockchain-future"&gt;Blockchain Forum&lt;/a&gt; with more questions.&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>python</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
