<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: 🦁 Yvonnick FRIN</title>
    <description>The latest articles on DEV Community by 🦁 Yvonnick FRIN (@yvonnickfrin).</description>
    <link>https://dev.to/yvonnickfrin</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F122502%2F58cc43aa-a935-4f77-af21-4575863671e8.jpg</url>
      <title>DEV Community: 🦁 Yvonnick FRIN</title>
      <link>https://dev.to/yvonnickfrin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yvonnickfrin"/>
    <language>en</language>
    <item>
      <title>I made my first game solo with Godot for a Game jam</title>
      <dc:creator>🦁 Yvonnick FRIN</dc:creator>
      <pubDate>Thu, 14 Mar 2024 10:34:30 +0000</pubDate>
      <link>https://dev.to/yvonnickfrin/i-made-my-first-game-solo-with-godot-for-a-game-jam-3lf8</link>
      <guid>https://dev.to/yvonnickfrin/i-made-my-first-game-solo-with-godot-for-a-game-jam-3lf8</guid>
      <description>&lt;p&gt;Hey 👋 During my holidays, I participated to a &lt;a href="https://itch.io/jam/acerola-jam-0"&gt;gamejam&lt;/a&gt;. The theme was aberration 👻 &lt;/p&gt;

&lt;p&gt;Here is my submission &lt;a href="https://itch.io/jam/acerola-jam-0/rate/2582646"&gt;https://itch.io/jam/acerola-jam-0/rate/2582646&lt;/a&gt;. It is an action-adventure game based on a short novel by Grant Allen (19th century).&lt;/p&gt;

&lt;p&gt;Feel free to rate and leave a comment 🤗&lt;/p&gt;

&lt;p&gt;I open sourced the code and assets: &lt;a href="https://github.com/frinyvonnick/pallinghurst-barrow"&gt;https://github.com/frinyvonnick/pallinghurst-barrow&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It was a cool experience. I had the opportunity to give a try to Procreate Dreams for the animations. It was my first time making a game with Godot. It is an easy-to-learn engine. I recommend it! In the past, I participated to a game jam with a mate. This time it was solo since it is the main rule of the jam. It lasted two weeks which was really intensive for me. I did most of the assets by myself except for audio. I don't know much about it.&lt;/p&gt;

&lt;p&gt;I recommend participating to jams. It forces you to make choices and goes straight to the point (which I struggle with most of the time)!&lt;/p&gt;

&lt;p&gt;You can contact me on Twitter &lt;a href="https://twitter.com/YvonnickFrin"&gt;@YvonnickFrin&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>godot</category>
      <category>procreate</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Setting up the development environment for js13k</title>
      <dc:creator>🦁 Yvonnick FRIN</dc:creator>
      <pubDate>Mon, 24 Aug 2020 11:19:59 +0000</pubDate>
      <link>https://dev.to/yvonnickfrin/setting-up-the-development-environment-20f2</link>
      <guid>https://dev.to/yvonnickfrin/setting-up-the-development-environment-20f2</guid>
      <description>&lt;p&gt;This article is the second entry of a devlog on my participation to &lt;a href="https://js13kgames.com/"&gt;js13k&lt;/a&gt; competition with &lt;a href="https://github.com/MogSogeking"&gt;MogSogeking&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;As we start developing our game, there are some tasks we want to avoid doing manually like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reloading our game each time we do some change;&lt;/li&gt;
&lt;li&gt;creating our submission file;&lt;/li&gt;
&lt;li&gt;checking if we reach the 13k limit;&lt;/li&gt;
&lt;li&gt;deploying our game to a public url (it is nice to gather feedback during development);&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before choosing a tool to help us achieve the tasks listed above it is important to know how our code must be structured. Here is the rule of js13k competition about the folder structure.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Your .zip package should contain index.html file in the top level folder structure&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Our entry point must be an index.html file that loads our JavaScript files. &lt;a href="https://parceljs.org"&gt;Parcel&lt;/a&gt; is a web application bundler that works with a html file as entry point. It requires almost no configuration. It seems to fit our needs so let's give it a try. &lt;/p&gt;

&lt;p&gt;Firstly, we install this new development dependency in our project.&lt;/p&gt;
&lt;h2&gt;
  
  
  Development server
&lt;/h2&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; &lt;span class="nt"&gt;--dev&lt;/span&gt; parcel-bundler
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;As explained in the &lt;a href="https://parceljs.org/getting_started.html"&gt;getting started&lt;/a&gt; section of the documentation, the default command of the cli launchs a development server. It will rebuild our game each time we change a file and refresh the JavaScript code opened in the browser (without reloading the whole page!). We add a &lt;code&gt;dev&lt;/code&gt; script to avoid typing this command each time we need it.&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="w"&gt;  &lt;/span&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;"parcel src/index.html"&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;Let's create a few files to test it. Here is our folder structure:&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;.&lt;/span&gt;
├── package-lock.json
├── package.json
└── src
    ├── index.html
    └── index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our &lt;code&gt;index.html&lt;/code&gt; file import our JavaScript code with a &lt;code&gt;script&lt;/code&gt; tag.&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;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./index.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To begin we add the well known &lt;strong&gt;Hello world!&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello world!&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;We start our dev server with the following 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 run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We should see a log &lt;code&gt;Hello world!&lt;/code&gt; in our browser console. I change the message in our console.log parameter with my first name and save the file.&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello Yvonnick!&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;Our browser has reloaded our code automatically and display the updated log 🎉&lt;/p&gt;

&lt;h2&gt;
  
  
  Submission file
&lt;/h2&gt;

&lt;p&gt;Our development server is set up. We need to generate our submission file which is a zip file containing our index.html, JavaScript files and other assets.&lt;/p&gt;

&lt;h3&gt;
  
  
  build
&lt;/h3&gt;

&lt;p&gt;The js13k rules says we can optimize our JavaScript code. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can use tools that minify JavaScript source code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Parcel cli has a &lt;a href="https://parceljs.org/cli.html#build"&gt;build&lt;/a&gt; command for this purpose. We add a few options to make it fill our needs.&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="w"&gt;  &lt;/span&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;"parcel src/index.html"&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;"parcel build src/index.html --no-source-maps --experimental-scope-hoisting --public-url ./"&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;Let's get some explanations about these options.&lt;/p&gt;

&lt;h4&gt;
  
  
  --public-url option
&lt;/h4&gt;

&lt;p&gt;Parcel prefixes the filename of the bundled javascript file with &lt;code&gt;public-url&lt;/code&gt; in the &lt;code&gt;index.html&lt;/code&gt; script tag. This option defaults to &lt;code&gt;/&lt;/code&gt;. It is fine for a website stored on a static server.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;when unzipped should work in the browser.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If we try to open the built &lt;code&gt;index.html&lt;/code&gt; we will see a blank page. Because the path of our JavaScript file is &lt;code&gt;/src.9905d997.js&lt;/code&gt;. It will look for our JavaScript file at system root. Setting &lt;code&gt;public-url&lt;/code&gt; to &lt;code&gt;./&lt;/code&gt; will fix this issue since it will look for our JavaScript file in the current folder. Now, it works just fine when we open the built &lt;code&gt;index.html&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  --no-source-maps option
&lt;/h4&gt;

&lt;p&gt;Source maps are files which reference a readable version of production that are most of the time minified. It helps us tracking bugs in our production bundle. Since our final zip size matters we don't want to include unnecessary files in it so we disable this feature. &lt;/p&gt;

&lt;h4&gt;
  
  
  --experimental-scope-hoisting option
&lt;/h4&gt;

&lt;p&gt;This option enables tree shaking during the build process. Tree shaking is a feature that prevents unused code of our dependencies being part of our production bundle. You can find out more in &lt;a href="https://medium.com/@devongovett/parcel-v1-9-0-tree-shaking-2x-faster-watcher-and-more-87f2e1a70f79#4ed3"&gt;this article&lt;/a&gt; of Devon Govett.&lt;/p&gt;

&lt;h3&gt;
  
  
  zip
&lt;/h3&gt;

&lt;p&gt;At last, we add a &lt;code&gt;zip&lt;/code&gt; script which creates a zip file with the content from &lt;code&gt;dist&lt;/code&gt; folder that is the output of our &lt;code&gt;build&lt;/code&gt; command.&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="w"&gt;  &lt;/span&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;"parcel src/index.html"&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;"parcel build src/index.html --no-source-maps --experimental-scope-hoisting --public-url ./"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"zip"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"zip -r submission.zip 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;Now, we can create our submission file using scripts 👌&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a CI/CD
&lt;/h2&gt;

&lt;p&gt;There are two last points to deal with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;checking if we reach the 13k limit&lt;/li&gt;
&lt;li&gt;deploying our game to a public url (it is nice to gather feedback during development)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We don't want to figure out at the end of the competition that our submission file doesn't not fit the requirements. We don't want either to type our commands manually each time we commit some change. Since we need to host our source code on Github we will use &lt;a href="https://github.com/features/actions"&gt;GitHub Actions&lt;/a&gt; to automate it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please provide two sources of your game - first one should be minified and zipped to fit in the 13 kB limit (sent via the form) and the second one should be in a readable form with descriptive variable names and comments (hosted on GitHub).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I wont explain how GitHub Actions works but you can find a lot of nice articles on &lt;a href="https://dev.to/search?q=GitHub%20Actions"&gt;dev.to&lt;/a&gt; on this topic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Checking our submission file size
&lt;/h3&gt;

&lt;p&gt;First of all, we need to add a script that checks our submission file size. We will use &lt;a href="https://github.com/siddharthkp/bundlesize"&gt;bundlesize&lt;/a&gt; to achieve it. It needs a bit of configuration (the file path to test, the max size it must not reach). We add it directly in our &lt;code&gt;package.json&lt;/code&gt; 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="nl"&gt;"bundlesize"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"submission.zip"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"maxSize"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"13 kB"&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;Then, we add a &lt;code&gt;size&lt;/code&gt; script that calls &lt;code&gt;bundlesize&lt;/code&gt;. It will throw an error if the zip file weight more than 13 kB.&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="err"&gt;//&lt;/span&gt;&lt;span class="w"&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;"size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bundlesize"&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;We create a first action in the file &lt;code&gt;.github/workflows/ci.yml&lt;/code&gt; that will call our freshly created &lt;code&gt;size&lt;/code&gt; script with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CI&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;CI&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v1&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run zip&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run size&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We trigger this action only on pull request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We create the zip file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run zip&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we run our &lt;code&gt;size&lt;/code&gt; script which will prevent us to merge if it fails.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run size&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, our CI checks for us our submission file size at each commit on pull request.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploying our game
&lt;/h3&gt;

&lt;p&gt;Cherry on the cake, we want to deploy our game on a public url so we can share it with friends to gather feedback during development. We create our second action in the file &lt;code&gt;.github/workflows/deploy.yml&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build-and-deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v1&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;JamesIves/github-pages-deploy-action@3.5.9&lt;/span&gt;
          &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
            &lt;span class="na"&gt;BRANCH&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gh-pages&lt;/span&gt; &lt;span class="c1"&gt;# The branch the action should deploy to.&lt;/span&gt;
            &lt;span class="na"&gt;FOLDER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dist&lt;/span&gt; &lt;span class="c1"&gt;# The folder the action should deploy.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We trigger this action only on master branch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use the action &lt;a href="https://github.com/JamesIves/github-pages-deploy-action"&gt;github-pages-deploy-action&lt;/a&gt; from &lt;a href="https://github.com/JamesIves"&gt;James Ives&lt;/a&gt; which deploy our code on &lt;a href="https://pages.github.com/"&gt;GitHub Pages&lt;/a&gt;. Our app will be available at the url &lt;code&gt;https://[your-handle].github.io/[repository-name]&lt;/code&gt; in my case &lt;a href="https://frinyvonnick.github.io/js13k-2020"&gt;https://frinyvonnick.github.io/js13k-2020&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We are all set 🙌 We can now develop our game at peace!&lt;/p&gt;




&lt;p&gt;Follow me on &lt;a href="https://dev.to/yvonnickfrin"&gt;dev.to&lt;/a&gt; or &lt;a href="https://twitter.com/YvonnickFrin"&gt;twitter&lt;/a&gt; if you want to be informed when a new blogpost of this serie is published!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>I participate in js13k this year</title>
      <dc:creator>🦁 Yvonnick FRIN</dc:creator>
      <pubDate>Fri, 21 Aug 2020 07:45:21 +0000</pubDate>
      <link>https://dev.to/yvonnickfrin/i-participate-in-js13k-this-year-32fj</link>
      <guid>https://dev.to/yvonnickfrin/i-participate-in-js13k-this-year-32fj</guid>
      <description>&lt;p&gt;I'm glad to announce I will participate in js13k this year with my buddy &lt;a href="https://github.com/MogSogeking"&gt;MogSogeking&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is js13k?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://js13kgames.com/"&gt;js13k&lt;/a&gt; is a game jam! But, what is a game jam? It is a competition where participants try to create a game from scratch in a limited time. js13k lasts a whole month and has a specific limitation. Your game must not weight over 13kb. Each year edition has a theme. This year's theme is &lt;strong&gt;404&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do I say it to you?
&lt;/h2&gt;

&lt;p&gt;I plan to share with you things I learn during this journey here on &lt;a href="https://dev.to/yvonnickfrin"&gt;dev.to&lt;/a&gt;. It will be mostly things on programming but also water cooler topics on graphism and music.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where can you track our progress?
&lt;/h2&gt;

&lt;p&gt;One rule of js13k competition is to share a readable form of your code on Github. Here is our &lt;a href="https://github.com/frinyvonnick/js13k-2020"&gt;repository&lt;/a&gt;. We will work with pull requests so feel free to sneak around and leave comments 😉&lt;/p&gt;




&lt;p&gt;The first blogpost on this journey will be about our project's development environment. Follow me on &lt;a href="https://dev.to/yvonnickfrin"&gt;dev.to&lt;/a&gt; or &lt;a href="https://twitter.com/YvonnickFrin"&gt;twitter&lt;/a&gt; if you want to be informed when a new blogpost is published!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>watercooler</category>
    </item>
    <item>
      <title>node-html-to-image v1.2 is out 🎉</title>
      <dc:creator>🦁 Yvonnick FRIN</dc:creator>
      <pubDate>Fri, 27 Mar 2020 11:03:54 +0000</pubDate>
      <link>https://dev.to/yvonnickfrin/node-html-to-image-v1-2-is-out-42f4</link>
      <guid>https://dev.to/yvonnickfrin/node-html-to-image-v1-2-is-out-42f4</guid>
      <description>&lt;p&gt;Sometime ago, I wrote a small module called &lt;a href="https://github.com/frinyvonnick/node-html-to-image"&gt;node-html-to-image&lt;/a&gt;. It generates images from HTML in Node.js. For more information, here is an &lt;a href="https://dev.to/yvonnickfrin/generate-images-from-html-in-node-js-8p5"&gt;article&lt;/a&gt; that explains how to use it. This week, it has been featured in &lt;a href="https://nodeweekly.com/issues/331"&gt;NodeWeekly&lt;/a&gt; 🎉&lt;/p&gt;

&lt;p&gt;This week, I also released version 1.2. Let's see what's new in &lt;code&gt;node-html-to-image&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  ✨ Transparency support
&lt;/h2&gt;

&lt;p&gt;This feature was asked by &lt;a href="https://github.com/jordan314"&gt;jordan314&lt;/a&gt;. It wasn't possible to have a transparent background for &lt;code&gt;png&lt;/code&gt; images. Here is an example to achieve it with the new &lt;code&gt;transparent&lt;/code&gt; option:&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;nodeHtmlToImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node-html-to-image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;nodeHtmlToImage&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./image.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;transparent&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;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;Hello world!&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The image was created successfully!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  📝 Improve documentation
&lt;/h2&gt;

&lt;p&gt;Users frequently asked me two questions about &lt;code&gt;node-html-to-image&lt;/code&gt; usage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to use locally stored images?&lt;/li&gt;
&lt;li&gt;How to set my image resolution?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I added two sections directly in the README that answer these questions (&lt;a href="https://github.com/frinyvonnick/node-html-to-image#setting-output-image-resolution"&gt;image resolution&lt;/a&gt; and &lt;a href="https://github.com/frinyvonnick/node-html-to-image#dealing-with-images"&gt;dealing with images&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;I hope it will help 🙏&lt;/p&gt;

&lt;h2&gt;
  
  
  ♻️ Simplify test setup
&lt;/h2&gt;

&lt;p&gt;I use &lt;a href="https://tesseract-ocr.github.io/"&gt;tesseract&lt;/a&gt; to test the module works fine. It was tricky to install the engine on your computer in order to run tests. I moved to &lt;a href="https://tesseract.projectnaptha.com/"&gt;tesseract.js&lt;/a&gt; which is a Javascript port of this OCR engine. Running yarn installation command is now enough to setup the project before running tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  💻 The CLI has been released too!
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;node-html-to-image&lt;/code&gt; has its own &lt;a href="https://github.com/frinyvonnick/node-html-to-image-cli"&gt;CLI&lt;/a&gt;. I think it is a good way to quickly give a try to the module. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4bIruEiA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://raw.githubusercontent.com/frinyvonnick/node-html-to-image-cli/master/misc/demo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4bIruEiA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://raw.githubusercontent.com/frinyvonnick/node-html-to-image-cli/master/misc/demo.gif" alt="node-html-to-image-cli demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What's new in &lt;code&gt;node-html-to-image-cli&lt;/code&gt; v1.1:
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Add an option to provide content
&lt;/h4&gt;

&lt;p&gt;It is now possible to use &lt;code&gt;handlebars&lt;/code&gt; with the CLI too. Here is an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx node-html-to-image-cli ./index.html ./image.png &lt;span class="nt"&gt;--content&lt;/span&gt; ./content.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;index.html:&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&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;h1&amp;gt;&lt;/span&gt;Hello {{you}}&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;content.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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
  &lt;/span&gt;&lt;span class="nl"&gt;"you"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"world"&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;Thanks to &lt;a href="https://github.com/jtanguy"&gt;Julien Tanguy&lt;/a&gt; 🙏&lt;/p&gt;

&lt;h4&gt;
  
  
  Add an option to support transparency
&lt;/h4&gt;

&lt;p&gt;I also added an option &lt;code&gt;transparent&lt;/code&gt; to enable support of transparency in the CLI too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx node-html-to-image-cli &lt;span class="nt"&gt;--type&lt;/span&gt; png &lt;span class="nt"&gt;--transparent&lt;/span&gt; ./index.html ./image.png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feel free check out the GitHub repositories if you are interested:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/frinyvonnick/node-html-to-image"&gt;node-html-to-image&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/frinyvonnick/node-html-to-image-cli"&gt;node-html-to-image-cli&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Want to support ? Don't forget to leave a ⭐️&lt;/p&gt;




&lt;p&gt;Feedback or ideas are appreciated 🙏 Please tweet me if you have questions &lt;a href="https://twitter.com/YvonnickFrin"&gt;@YvonnickFrin&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>node</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>A guide on commit messages</title>
      <dc:creator>🦁 Yvonnick FRIN</dc:creator>
      <pubDate>Wed, 29 Jan 2020 13:11:00 +0000</pubDate>
      <link>https://dev.to/yvonnickfrin/a-guide-on-commit-messages-d8n</link>
      <guid>https://dev.to/yvonnickfrin/a-guide-on-commit-messages-d8n</guid>
      <description>&lt;p&gt;The comic is from &lt;a href="http://turnoff.us/"&gt;Daniel Stori&lt;/a&gt;. It is licensed under &lt;a href="http://creativecommons.org/licenses/by-nc-sa/4.0/"&gt;a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;The time you had an archive file on your disk called "version 1" should be far away. I bet you use some tool for version control like GitHub, Gitlab, Bitbucket, ... So you must write commits everytime you want to add your code to a project. Have you ever wondered if your commits messages are good? Maybe you don't like writing them and wonder why you have to do it every time you want to push code. After all, isn't the change sufficient enough? &lt;/p&gt;

&lt;p&gt;In this article, we will talk about writing &lt;em&gt;good commit messages&lt;/em&gt;, and not &lt;em&gt;good commits&lt;/em&gt;, even if these two subjects are closely linked (here is a &lt;a href="https://www.git-tower.com/blog/version-control-best-practices/"&gt;good article&lt;/a&gt; from Tobias Günther that summarize well best practices about version control).&lt;/p&gt;
&lt;h2&gt;
  
  
  Why commit messages are important?
&lt;/h2&gt;

&lt;p&gt;So, is the change sufficient? Obviously, the answer is no. But why?&lt;/p&gt;

&lt;p&gt;Commit messages have a lot of uses. This is the first way to communicate with your fellow developers on a project. The change defines &lt;em&gt;how&lt;/em&gt; you achieve something but the commit message explains &lt;em&gt;why&lt;/em&gt; you are doing it. It must give enough context to avoid a developper to wonder why some code is written like that. With proper explanations you won't spend precious time asking yourself why a developer pushed this code. In some cases like open source projects, busy maintainers won't even read your code if you don't give them a minimum of information like a nicely written commit message.&lt;/p&gt;

&lt;p&gt;Commit messages are not only for your coworkers but also for your future self as Peter Hutterer said in this great article &lt;a href="http://who-t.blogspot.com/2009/12/on-commit-messages.html"&gt;On commit messages&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Any software project is a collaborative project. It has at least two developers, the original developer and the original developer a few weeks or months later when the train of thought has long left the station.&lt;/p&gt;

&lt;p&gt;Peter Hutterer - &lt;a href="http://who-t.blogspot.com/2009/12/on-commit-messages.html"&gt;On commit messages&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A project is designed to be maintained in the long term. Sometimes years after a piece of code was written, you may ask yourself why it has been written like that. It happened to me this week with a function I coded only 6 months ago. With a well written commit message, it is easier to get back in the state of mind at the time you wrote this change.&lt;/p&gt;

&lt;p&gt;Taking care of your commit messages can also simplify your daily life. Some tools becomes more interesting with a meaningful commit history like a few git commands &lt;code&gt;log&lt;/code&gt;, &lt;code&gt;rebase&lt;/code&gt;, &lt;code&gt;cherry-pick&lt;/code&gt;, ... When you come back from holidays a simple &lt;code&gt;git log --pretty&lt;/code&gt; will give you a lot of information about what your coworkers did while you were away. Writing good commit messages forces you to split your change, making it easier to review with &lt;code&gt;git log -p&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Speaking of review, did you ever struggle rebasing your code on some change a developer made? It becomes easier to know why a change was made if the commit message carries real meaning. It makes &lt;code&gt;rebase&lt;/code&gt; result much more predictible. Another example is &lt;code&gt;git blame&lt;/code&gt; command which, by the way, isn't there to make fun of your colleagues, but to give you context on a specific line of code. It can be pretty useful when you want to refactor a piece of code. &lt;/p&gt;

&lt;p&gt;Last but not least, a well structured commit history allows changelog generation between two versions of your project to inform your users what changed.&lt;/p&gt;

&lt;p&gt;This is a huge amount of reasons to start taking time to write good commit messages.&lt;/p&gt;
&lt;h2&gt;
  
  
  How to write a good commit message
&lt;/h2&gt;

&lt;p&gt;Now that you are convinced commit messages are important, let's talk about how to write good ones. I picked commit messages from a project I work on called &lt;a href="https://github.com/zenika-open-source/immutadot"&gt;immutadot&lt;/a&gt;. As you can see, these commit messages are not consistent, which makes them hard to read.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fix #72 unnecessary object copies
Fixing unshift documentation examples
seq.chain path parameter fix #18
Remove built files
Add tests
Add Circle CI base config
Rename es -&amp;gt; src
Add lang package with toggle, fix exports
Core package
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In these commit messages, we can see a few mistakes in term of style, content and metadata. Chris Beams accurately describes these three points in his article &lt;a href="https://chris.beams.io/posts/git-commit/"&gt;How to Write a Git Commit Message&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Style. Markup syntax, wrap margins, grammar, capitalization, punctuation. Spell these things out, remove the guesswork, and make it all as simple as possible. The end result will be a remarkably consistent log that’s not only a pleasure to read but that actually does get read on a regular basis.&lt;/p&gt;

&lt;p&gt;Content. What kind of information should the body of the commit message (if any) contain? What should it not contain?&lt;/p&gt;

&lt;p&gt;Metadata. How should issue tracking IDs, pull request numbers, etc. be referenced?&lt;/p&gt;

&lt;p&gt;Chris Beams - &lt;a href="https://chris.beams.io/posts/git-commit/"&gt;How to Write a Git Commit Message&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We can see there are capitalized messages, metadata for only two commits... Eventually, some messages content are so light we can't figure out what the commit does. In the same article, Chris goes through 7 rules to write a good commit message :&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Separate subject from body with a blank line&lt;/li&gt;
&lt;li&gt;Limit the subject line to 50 characters&lt;/li&gt;
&lt;li&gt;Capitalize the subject line&lt;/li&gt;
&lt;li&gt;Do not end the subject line with a period&lt;/li&gt;
&lt;li&gt;Use the imperative mood in the subject line&lt;/li&gt;
&lt;li&gt;Wrap the body at 72 characters&lt;/li&gt;
&lt;li&gt;Use the body to explain what and why vs. how&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Chris Beams - &lt;a href="https://chris.beams.io/posts/git-commit/"&gt;How to Write a Git Commit Message&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I personnally apply a subset of these rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Limit the subject line to 50 characters&lt;/li&gt;
&lt;li&gt;Capitalize the subject line&lt;/li&gt;
&lt;li&gt;Use the imperative mood in the subject line&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not only does the character limit force you to be concise, which is a great skill, but it fits well with a lot of tools as explained in Tim Pope article &lt;a href="https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html"&gt;A Note About Git Commit Messages&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I tend to think the perfect is the enemy of the good. That is why I omitted talking about commit messages body. I think we have enough work to do on the summary line. But I would add one rule as counterpart:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a pull request/merge request tracking ID&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most of the time, we use tools to discuss during a code review process like GitHub, Gitlab, ... All pieces of information about the change will be at least described there. I added this rule about tracking ID so it becomes easy to find related pull/merge request. Writing a commit body is better than adding tracking IDs because if you change your repository manager solution, you will lose all this precious context information and your tracking IDs will be useless.&lt;/p&gt;

&lt;p&gt;Here is a more recent example from a project I work on called &lt;a href="https://github.com/frinyvonnick/gitmoji-changelog"&gt;gitmoji-changelog&lt;/a&gt; that follow these rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Make core independent from the git client (#171)
Upgrade Docker image version (#167)
Add maven preset (#172)
Add a generic preset using configuration file (#160)
Improve error messages for preset system (#161)
Publish Canary version on master push (#141)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Having a consistent style makes it much more easier to read. You can figure out the context of the change, and metadata are directly accessible. The most important thing is to find common rules in your team to ensure having a well structured commit history. There are some conventions that can help you finding these but we will be back on this subject later.&lt;/p&gt;

&lt;p&gt;If you have difficulties to find out what message you should write, maybe you should split your commit in smaller parts. Peter Hutterer listed in his article &lt;a href="http://who-t.blogspot.com/2009/12/on-commit-messages.html"&gt;On commit messages&lt;/a&gt; a few examples where it is difficult to find out a good commit message because your commit patch may not be logical.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bonus
&lt;/h3&gt;

&lt;p&gt;If you use practices like pair or mob programming, don't forget to add your coworkers names in your commit messages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git commit -m "Refactor usability tests.
&amp;gt;
&amp;gt;
Co-authored-by: name &amp;lt;name@example.com&amp;gt;
Co-authored-by: another-name &amp;lt;another-name@example.com&amp;gt;"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Commit conventions
&lt;/h2&gt;

&lt;p&gt;As written in the previous section, you should define a commit convention for your team. It exists open source commit conventions that could be a good source of inspiration. They also come with a whole ecosystem that includes tools to help you write commit messages, generate changelog, create releases, ... A lot of things that can take a large amount of time. There are well documented so you don't have to write documentation about your own commit message convention.&lt;/p&gt;

&lt;p&gt;We will talk about two of them &lt;a href="https://conventionalcommits.org"&gt;Conventional Commits&lt;/a&gt; and &lt;a href="https://gitmoji.carloscuesta.me/"&gt;gitmoji&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conventional Commits
&lt;/h3&gt;

&lt;p&gt;It is a specification inspired from &lt;a href="https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#-commit-message-guidelines"&gt;Angular commit message guidelines&lt;/a&gt;. It features a few interesting rules like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Commit must be prefixed with a type (feat, fix)&lt;/li&gt;
&lt;li&gt;A scope may be provided to point out a specific section of a the codebase (really interesting for monorepos)&lt;/li&gt;
&lt;li&gt;Breaking changes must be included in a footer section&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is how a commit message must be structured using this specification:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;type&amp;gt;[optional scope]: &amp;lt;description&amp;gt;

[optional body]

[optional footer(s)]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read more in their &lt;a href="https://www.conventionalcommits.org/en/v1.0.0/#specification"&gt;specification section&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  gitmoji
&lt;/h3&gt;

&lt;p&gt;I'm fond of gitmoji commit convention. It lies on categorizing commits using emojies. I'm a visual person so it fits well to me but I understand this convention is not made for everyone.&lt;/p&gt;

&lt;p&gt;I was not totally honest in my previous commit examples from &lt;a href="https://github.com/frinyvonnick/gitmoji-changelog"&gt;gitmoji-changelog&lt;/a&gt;. There is a missing part as you should have guessed now.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:recycle: Make core independent from the git client (#171)
:whale: Upgrade Docker image version (#167)
:sparkles: Add maven preset (#172)
:sparkles: Add a generic preset using configuration file (#160)
:recycle: Improve error messages for preset system (#161)
:construction_worker: Publish Canary version on master push (#141)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These text aliases are widely used in tools like Slack, Discord, ... Most of the repository manager tools like GitHub or GitLab interprets them and display it well in their UI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;♻️ Make core independent from the git client (#171)
🐳 Upgrade Docker image version (#167)
✨ Add maven preset (#172)
✨ Add a generic preset using configuration file (#160)
♻️ Improve error messages for preset system (#161)
👷‍♂️ Publish Canary version on master push (#141)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I like this convention because I know at first glance what kind of change do a commit. It comes with a cli called &lt;a href="https://github.com/carloscuesta/gitmoji-cli"&gt;gitmoji-cli&lt;/a&gt; that helps you write your commit messages and I made a changelog generator for it.&lt;/p&gt;

&lt;p&gt;There are more of them. Keep in mind that these are guidelines, you can mix them to get something that fills your need. For example, using gitmoji convention with the scope notion of conventional commits if you work on a monorepo.&lt;/p&gt;




&lt;p&gt;Feedback is appreciated 🙏 Please tweet me if you have any questions &lt;a href="https://twitter.com/YvonnickFrin"&gt;@YvonnickFrin&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>git</category>
      <category>codequality</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Share good resources to start with Ember.js</title>
      <dc:creator>🦁 Yvonnick FRIN</dc:creator>
      <pubDate>Wed, 22 Jan 2020 12:46:42 +0000</pubDate>
      <link>https://dev.to/yvonnickfrin/share-good-resources-to-start-with-ember-js-p89</link>
      <guid>https://dev.to/yvonnickfrin/share-good-resources-to-start-with-ember-js-p89</guid>
      <description>&lt;p&gt;Hi 👋&lt;/p&gt;

&lt;p&gt;Next month, I will start to work for a new customer. Their project is made with Ember.js so I need to learn developing with this framework. When I learn something new I like to have a side project that keeps me motivated. So yesterday, I bootstrapped a website with &lt;code&gt;ember-cli&lt;/code&gt; for my project &lt;a href="https://github.com/frinyvonnick/gitmoji-changelog"&gt;gitmoji-changelog&lt;/a&gt;. In a couple of hours, I made a working MVP 🎉 (if you are interested in making a code review here is the &lt;a href="https://github.com/frinyvonnick/gitmoji-changelog/pull/175"&gt;pull request&lt;/a&gt;). Here is the result (this is still a work in progress):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dTjBQDqT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://user-images.githubusercontent.com/13099512/72843094-18631c00-3c9a-11ea-8f32-cd8cc70a75d1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dTjBQDqT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://user-images.githubusercontent.com/13099512/72843094-18631c00-3c9a-11ea-8f32-cd8cc70a75d1.gif" alt="gitmoji-changelog website"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I only used the documentation to achieve it which is really nice! I don't like to look for basics in a search engine when I start learning a new framework. The work done on documentation is really impressive. There are still a lot of things I need to read in it. But... I want more!&lt;/p&gt;

&lt;p&gt;I'm looking for more resources to learn about good practises, architecture, ... I found an &lt;a href="https://github.com/ember-community-russia/awesome-ember"&gt;awesome-ember&lt;/a&gt; repository but there are a lot of links! I don't know where to start.&lt;/p&gt;

&lt;p&gt;What are your recommended resources for beginners that want to learn more about advanced topics on Ember.js?&lt;/p&gt;

</description>
      <category>ember</category>
      <category>javascript</category>
      <category>discuss</category>
      <category>beginners</category>
    </item>
    <item>
      <title>react-simple-infinite-loading v1 is out 🎉</title>
      <dc:creator>🦁 Yvonnick FRIN</dc:creator>
      <pubDate>Wed, 15 Jan 2020 12:47:53 +0000</pubDate>
      <link>https://dev.to/yvonnickfrin/react-simple-infinite-loading-v1-is-out-439f</link>
      <guid>https://dev.to/yvonnickfrin/react-simple-infinite-loading-v1-is-out-439f</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/bvaughn/react-window"&gt;react-window&lt;/a&gt; is an awesome tool but it can be a bit verbose when implementing infinite loading list. Here is an &lt;a href="https://codesandbox.io/s/x70ly749rq"&gt;example&lt;/a&gt;. &lt;a href="https://github.com/frinyvonnick/react-simple-infinite-loading"&gt;react-simple-infinite-loading&lt;/a&gt; is a component that handles code complexity for you. It is a wrapper around three libraries from &lt;a href="https://github.com/bvaughn"&gt;Brian Vaughn&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/bvaughn/react-window"&gt;react-window&lt;/a&gt; is made to display efficiently large lists. It only creates components for the visible elements and reuse nodes.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/bvaughn/react-window-infinite-loader/"&gt;react-window-infinite-loader&lt;/a&gt; is a HOC that loads elements just-in-time as user scrolls down the list&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/bvaughn/react-virtualized-auto-sizer/"&gt;react-virtualized-auto-sizer&lt;/a&gt; helps you displaying your list so it fits the space available in its parent container.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--I2ZqTeyb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://yvonnickfrin.dev/images/react-simple-infinite-loading.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--I2ZqTeyb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://yvonnickfrin.dev/images/react-simple-infinite-loading.gif" alt="react-simple-infinite-loading demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  v1 is out!
&lt;/h2&gt;

&lt;p&gt;The component now have a complete set of features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Load items as the user scrolls down&lt;/li&gt;
&lt;li&gt;Use internal methods to scroll programmatically or reset cached items&lt;/li&gt;
&lt;li&gt;Override default scrollbar style&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;Let's go through the minimal example.&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="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;InfiniteLoading&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-simple-infinite-loading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fetchMore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hasMore&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;InfiniteLoading&lt;/span&gt;
        &lt;span class="nx"&gt;hasMoreItems&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hasMore&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;itemHeight&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;loadMoreItems&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;fetchMore&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/InfiniteLoading&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;&lt;code&gt;react-simple-infinite-loading&lt;/code&gt; requires four properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;children&lt;/strong&gt;: It should be an array of JSX nodes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;hasMoreItems&lt;/strong&gt;: this property determine if the user reached the end of the list so it prevents him to scroll further.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;itemHeight&lt;/strong&gt;: it is mandatory to optimize number of elements rendered and determine if more rows need to be loaded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;loadMoreItems&lt;/strong&gt;: a callback function the component will call when more rows need to be loaded.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hide &lt;code&gt;loadMoreItems&lt;/code&gt; function implementation on purpose since it depends on your context. It may be a fetch call, GraphQL query, database access, whatever you want. You can see a complete example using &lt;a href="https://swapi.co/"&gt;Star Wars API&lt;/a&gt; in the &lt;a href="https://github.com/frinyvonnick/react-simple-infinite-loading/tree/master/example"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Override default scrollbar style
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;react-simple-infinite-loading&lt;/code&gt; use &lt;a href="https://github.com/malte-wessel/react-custom-scrollbars"&gt;react-custom-scrollbars&lt;/a&gt; under the hood to override native scrollbar style. You need to add the prop &lt;code&gt;customScrollbar&lt;/code&gt; to enable it.&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="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;InfiniteLoading&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-simple-infinite-loading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fetchMore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hasMore&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;InfiniteLoading&lt;/span&gt;
        &lt;span class="nx"&gt;hasMoreItems&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hasMore&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;itemHeight&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;loadMoreItems&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;fetchMore&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;customScrollbar&lt;/span&gt;
      &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/InfiniteLoading&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Display a placeholder while loading more rows
&lt;/h2&gt;

&lt;p&gt;You can set a &lt;code&gt;placeholder&lt;/code&gt; property that will be displayed while the rows are loading. By default it adds an extra row at the end of the list with the &lt;code&gt;placeholder&lt;/code&gt; node as content.&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="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;InfiniteLoading&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-simple-infinite-loading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fetchMore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hasMore&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;InfiniteLoading&lt;/span&gt;
        &lt;span class="nx"&gt;hasMoreItems&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hasMore&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;itemHeight&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;loadMoreItems&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;fetchMore&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;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;Loading&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;      &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/InfiniteLoading&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--I2ZqTeyb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://yvonnickfrin.dev/images/react-simple-infinite-loading.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--I2ZqTeyb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://yvonnickfrin.dev/images/react-simple-infinite-loading.gif" alt="react-simple-infinite-loading demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to have a placeholder by row that will be loaded you need to provide the optional property &lt;code&gt;itemsCount&lt;/code&gt; (It only works if you know the number of rows in advance). There is a counterpart, you will need to have a more fine-grained implementation of &lt;code&gt;loadMoreItems&lt;/code&gt; callback. This function takes as parameter a start index and a end index of rows that need to be loaded.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--X42G6Ap_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://yvonnickfrin.dev/images/react-simple-infinite-loading-placeholder.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X42G6Ap_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://yvonnickfrin.dev/images/react-simple-infinite-loading-placeholder.gif" alt="react-simple-infinite-loading demo with multiple placeholders"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Call internal methods
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;react-window&lt;/code&gt; and &lt;code&gt;react-window-infinite-loader&lt;/code&gt; exposes a few methods to manipulate the list programmatically. You can use it through a ref.&lt;/p&gt;

&lt;p&gt;You have access to three methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;scrollTo(scrollOffset: number): void&lt;/strong&gt; - Scroll to a specified offset.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;scrollToItem(index: number, align: string = "auto"): void&lt;/strong&gt; - Scroll to a specified item. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;resetloadMoreItemsCache(): void&lt;/strong&gt; - Clear previously loaded items from cache.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is an example with the &lt;code&gt;scrollTo&lt;/code&gt; method.&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;Example&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fetchMore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hasMore&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="o"&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;useRef&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;scrollToTop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scrollTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="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="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;scrollToTop&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Scroll&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;top&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;InfiniteLoading&lt;/span&gt;
          &lt;span class="nx"&gt;hasMoreItems&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hasMore&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;itemHeight&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;loadMoreItems&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;fetchMore&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/InfiniteLoading&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="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--aSx98R9T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://yvonnickfrin.dev/images/react-simple-infinite-loading-scroll-top.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aSx98R9T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://yvonnickfrin.dev/images/react-simple-infinite-loading-scroll-top.gif" alt="react-simple-infinite-loading demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are interested feel free to give it a try!&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/frinyvonnick/react-simple-infinite-loading"&gt;https://github.com/frinyvonnick/react-simple-infinite-loading&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feedback and contributions are appreciated 🙏 Please tweet me if you have any questions &lt;a href="https://twitter.com/YvonnickFrin"&gt;@YvonnickFrin&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Hope it will help!&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>showdev</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Shutdown correctly Node.js app</title>
      <dc:creator>🦁 Yvonnick FRIN</dc:creator>
      <pubDate>Thu, 09 Jan 2020 12:19:23 +0000</pubDate>
      <link>https://dev.to/yvonnickfrin/shutdown-correctly-node-js-app-39jc</link>
      <guid>https://dev.to/yvonnickfrin/shutdown-correctly-node-js-app-39jc</guid>
      <description>&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@lemonzandtea?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Aleksandar Cvetanovic&lt;/a&gt; on &lt;a href="https://unsplash.com/" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;It is important to shutdown correctly your apps to handle well processing requests and prevent it to accept new ones. I'll take a web server as example.&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;http&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="s1"&gt;http&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;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeHead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&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="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/plain&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello World&lt;/span&gt;&lt;span class="se"&gt;\n&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="mi"&gt;4000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9090&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;listening http://localhost:9090/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pid is &lt;/span&gt;&lt;span class="dl"&gt;'&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;pid&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;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fyvonnickfrin.dev%2F%2Fimages%2Fkill-server.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fyvonnickfrin.dev%2F%2Fimages%2Fkill-server.gif" alt="Error when killing server"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we see our server doesn't shutdown properly and processing requests don't get right responses. First of all we need to understand how a Node process is terminated in order to fix it.&lt;/p&gt;

&lt;p&gt;A process receives a signal when it is about to be killed. They are different kind of &lt;a href="http://man7.org/linux/man-pages/man7/signal.7.html" rel="noopener noreferrer"&gt;signals&lt;/a&gt;. We will focus on three of them in particular:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SIGINT: Quit from keyboard (Ctrl + C).&lt;/li&gt;
&lt;li&gt;SIGQUIT: Quit from keyboard (Ctrl + \). It also produce a &lt;a href="http://man7.org/linux/man-pages/man5/core.5.html" rel="noopener noreferrer"&gt;core dump&lt;/a&gt; file.&lt;/li&gt;
&lt;li&gt;SIGTERM: Quit from operating system (using kill command for example).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Node.js emits events when the process receives signals. You can write a handler for these events. In this one we will close our server so it deals with pending requests and prevent getting new ones.&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;// ...&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Received &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;. Close my server properly.`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SIGINT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleExit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SIGQUIT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleExit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SIGTERM&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleExit&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://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fyvonnickfrin.dev%2F%2Fimages%2Fkill-server-properly.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fyvonnickfrin.dev%2F%2Fimages%2Fkill-server-properly.gif" alt="Handle well killing server"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now our server handles well the request then shutdown correctly. You can read more in &lt;a href="https://twitter.com/nairihar" rel="noopener noreferrer"&gt;Nairi Harutyunyan&lt;/a&gt;'s &lt;a href="https://medium.com/hackernoon/graceful-shutdown-in-nodejs-2f8f59d1c357" rel="noopener noreferrer"&gt;nice article&lt;/a&gt;. It explain in details how to shutdown properly a server with a database.&lt;/p&gt;

&lt;p&gt;It also exists an node module that handles this logic for you called &lt;a href="https://www.npmjs.com/package/death" rel="noopener noreferrer"&gt;death&lt;/a&gt; (made by &lt;a href="https://github.com/jprichardson" rel="noopener noreferrer"&gt;JP Richardson&lt;/a&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ON_DEATH&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="s1"&gt;death&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nc"&gt;ON_DEATH&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// clean up code here&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h2&gt;
  
  
  Sometimes it is not enough
&lt;/h2&gt;

&lt;p&gt;I ran into a situation recently where my server needed to accept new requests in order to shutdown properly. I'll give some explanations. My server subscribed to a webhook. This webhook has a limited quota of subscriptions. So if I don't want to exceed this quota I need to unsubscribe properly when my server shutdown. Here is the unsubscription workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Send a request to the webhhook to unsubscribe&lt;/li&gt;
&lt;li&gt;The webhook sent a request to the server to confirm unsubscription&lt;/li&gt;
&lt;li&gt;The server must respond with a specific token to validate the unsubscription&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A Node.js process will close automatically if its event loop is empty. As you can see between 1. and 2. the event loop is empty so the process will be terminated and we won't be able to unsubscribe successfully.&lt;/p&gt;

&lt;p&gt;Here is the new server codebase we will 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;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;qs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;?&lt;/span&gt;&lt;span class="dl"&gt;"&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeHead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;challenge&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;end&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeHead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&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="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9090&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;listening http://localhost:9090/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pid is &lt;/span&gt;&lt;span class="dl"&gt;'&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;pid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3000/webhook?mode=subscribe&amp;amp;callback=http://localhost:9090&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;There are two changes. When the server starts listening on port 9090 we send a first request to subscribe our server to the webhook.&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;// ...&lt;/span&gt;

&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3000/webhook?mode=subscribe&amp;amp;callback=http://localhost:9090&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also changed our server's request handler to let him confirm the subscription to the webhook by responding with the token called &lt;code&gt;challenge&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;// ...&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;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeHead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;challenge&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&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="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's change the &lt;code&gt;handleExit&lt;/code&gt; function's implementation to send a request to our webhook. We ask the webhook to unsubcribe our server.&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;handleExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Received &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;. Close my server properly.`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3000/webhook?mode=unsubscribe&amp;amp;callback=http://localhost:9090&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;We need to update the code that responds with the challenge to kill our server's process when the webhook confirms the unsubscription.&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;// ...&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;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeHead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;challenge&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&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;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unsubscribe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="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="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the webhook confirms the unsubscription, we close our server so it stops getting new requests and exits our process properly. This is how the &lt;a href="https://dev.twitch.tv/docs/api/webhooks-guide" rel="noopener noreferrer"&gt;Twitch API&lt;/a&gt; webhooks subscription/unsubscription works.&lt;/p&gt;

&lt;p&gt;Let's see how our server acts when we try to shut it down. I added some logs to make it more visual.&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%2Fyvonnickfrin.dev%2F%2Fimages%2Fkill-webhook.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fyvonnickfrin.dev%2F%2Fimages%2Fkill-webhook.gif" alt="Error when killing server with webhook"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, it doesn't shutdown properly. The server's process is terminated before we get the webhook request that confirms unsubscription. So the webhook keeps sending events to our server.&lt;/p&gt;

&lt;p&gt;To fix this we need to prevent the Node.js process from exiting. We can use the method &lt;code&gt;process.stdin.resume&lt;/code&gt; that causes the process to pause and override disable default behavior like exiting on &lt;code&gt;Ctrl+C&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;http&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="s1"&gt;http&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resume&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now?&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%2Fyvonnickfrin.dev%2F%2Fimages%2Fkill-webhook-properly.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fyvonnickfrin.dev%2F%2Fimages%2Fkill-webhook-properly.gif" alt="Error when killing server with webhook properly"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nice, it now waits for the confirmation before exiting the process.&lt;/p&gt;

&lt;p&gt;I made a &lt;a href="https://github.com/frinyvonnick/node-shutdown-properly-webhooks" rel="noopener noreferrer"&gt;repository&lt;/a&gt; with all the sources presented in this article.&lt;/p&gt;

&lt;p&gt;Hope it will help 🙌&lt;/p&gt;




&lt;p&gt;Feedback is appreciated 🙏 Please tweet me if you have any questions &lt;a href="https://twitter.com/YvonnickFrin" rel="noopener noreferrer"&gt;@YvonnickFrin&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>beginners</category>
      <category>node</category>
      <category>javascript</category>
    </item>
    <item>
      <title>What would you like to learn in 2020?</title>
      <dc:creator>🦁 Yvonnick FRIN</dc:creator>
      <pubDate>Wed, 01 Jan 2020 15:04:47 +0000</pubDate>
      <link>https://dev.to/yvonnickfrin/what-would-you-like-to-learn-in-2020-i58</link>
      <guid>https://dev.to/yvonnickfrin/what-would-you-like-to-learn-in-2020-i58</guid>
      <description>&lt;p&gt;As developers we have to learn new things on a daily basis. It is a being a while since I want to learn something not related to my current work. I'm interested in the idea of learning a new language. I mainly code in JavaScript it could be refreshing to see other syntaxes. I guess it will be my main goal this year.&lt;/p&gt;

&lt;p&gt;What is the thing you absolutely want to learn in 2020?&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>challenge</category>
      <category>career</category>
      <category>motivation</category>
    </item>
    <item>
      <title>OCR in JavaScript with Tesseract.js</title>
      <dc:creator>🦁 Yvonnick FRIN</dc:creator>
      <pubDate>Tue, 24 Dec 2019 09:21:30 +0000</pubDate>
      <link>https://dev.to/yvonnickfrin/ocr-in-javascript-with-tesseract-hnl</link>
      <guid>https://dev.to/yvonnickfrin/ocr-in-javascript-with-tesseract-hnl</guid>
      <description>&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@mrasmuson?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Mark Rasmuson&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/handwritten?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;While making &lt;a href="https://github.com/frinyvonnick/node-html-to-image" rel="noopener noreferrer"&gt;node-html-to-image&lt;/a&gt; I came across a small problem. How to test it actually works? &lt;code&gt;node-html-to-image&lt;/code&gt; is a Node.js module that generates images (png, jpeg) from HTML. If you want to learn more about it I wrote a &lt;a href="https://dev.to/yvonnickfrin/generate-images-from-html-in-node-js-8p5"&gt;small article&lt;/a&gt; about this module. The simplest test I could imagine to ensure it works was creating an image from an HTML string containing "Hello world!". Then I could check the image really contains this string using &lt;a href="https://en.wikipedia.org/wiki/Optical_character_recognition" rel="noopener noreferrer"&gt;OCR&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is OCR?
&lt;/h2&gt;

&lt;p&gt;OCR stands for optical character recognition. This technology let you extract text from an image. It can be handrwritten or printed text. OCR involves a lot a complex steps to actually get text from an image but it isn't the prupose of this article. You can learn more reading its &lt;a href="https://en.wikipedia.org/wiki/Optical_character_recognition" rel="noopener noreferrer"&gt;wikipedia's article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We will focus on how to use it with the most popular open source OCR engine, &lt;a href="https://github.com/tesseract-ocr/tesseract" rel="noopener noreferrer"&gt;Tesseract&lt;/a&gt;. As a lib it is available for C/C++ developpers. Fortunately, it exists a port in JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Tesseract.js&lt;/code&gt; doesn't need you to install anything on your computer unlike &lt;a href="https://github.com/zapolnoch/node-tesseract-ocr" rel="noopener noreferrer"&gt;node-tesseract-ocr&lt;/a&gt;. It also means it doesn't work offline. &lt;code&gt;node-tesseract-ocr&lt;/code&gt; is only a wrapper around &lt;code&gt;tesseract&lt;/code&gt; so you need to install &lt;code&gt;tesseract&lt;/code&gt; and &lt;code&gt;tesseract-lang&lt;/code&gt; on your computer. While &lt;code&gt;Tesseract.js&lt;/code&gt; downloads languages and core scripts on the go.&lt;/p&gt;

&lt;p&gt;The only thing you need to do is installing npm package &lt;code&gt;Tesseract.js&lt;/code&gt; using your favorite package manager:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# With yarn&lt;/span&gt;
yarn add tesseract.js
&lt;span class="c"&gt;# With npm&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;tesseract.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Here is the image we will try to extract text from.&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%2Fyvonnickfrin.dev%2Fimages%2Fhello-world.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%2Fyvonnickfrin.dev%2Fimages%2Fhello-world.png" alt="An image with Hello world in it"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's go through it step by step.&lt;/p&gt;

&lt;p&gt;First of all we need to import the &lt;code&gt;createWorker&lt;/code&gt; function.&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;createWorker&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="s1"&gt;tesseract.js&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;We call it to create a new tesseract worker which is a Child Process in Node.js and a Web Worker in the browser (yes, Tesseract.js also work in the browser).&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;worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createWorker&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A worker instance have several methods. The first we need to call is the &lt;a href="https://github.com/naptha/tesseract.js/blob/master/docs/api.md#workerloadjobid-promise" rel="noopener noreferrer"&gt;load&lt;/a&gt; function. It loads core scripts and prepare tesseract worker for what's coming next.&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;// ...&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getTextFromImage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&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;Then, we need to load the language of the text in our image. We can achieve it with &lt;a href="https://github.com/naptha/tesseract.js/blob/master/docs/api.md#workerloadlanguagelangs-jobid-promise" rel="noopener noreferrer"&gt;loadLanguages&lt;/a&gt; method. I will download a file with trained date for the language in it. In our example, it will be a file called &lt;code&gt;eng.traineddata&lt;/code&gt;. We can load more than one language using &lt;code&gt;+&lt;/code&gt; character (ex: &lt;code&gt;eng+fr&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;// ...&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getTextFromImage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadLanguage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eng&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;Time to make our worker ready to do OCR tasks. We do it with the &lt;a href="https://github.com/naptha/tesseract.js/blob/master/docs/api.md#workerinitializelangs-oem-jobid-promise" rel="noopener noreferrer"&gt;initialize&lt;/a&gt; method. It takes language we want to use as parameters. It can be a subset of the languages we loaded earlier.&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;// ...&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getTextFromImage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadLanguage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eng&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eng&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;Let's do OCR! Our worker has a &lt;a href="https://github.com/naptha/tesseract.js/blob/master/docs/api.md#workerrecognizeimage-options-jobid-promise" rel="noopener noreferrer"&gt;recognize&lt;/a&gt; method that takes an image as parameter. It can be an url, a path on the file system or a buffer. It returns a object with a data property that also is an object with a text property in it containing the final result.&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;// ...&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getTextFromImage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadLanguage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eng&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eng&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recognize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./hello-world.png&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;Last step we need to clean up our worker using the method &lt;a href="https://github.com/naptha/tesseract.js/blob/master/docs/api.md#workerterminatejobid-promise" rel="noopener noreferrer"&gt;terminate&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getTextFromImage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadLanguage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eng&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eng&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recognize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./hello-world.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;terminate&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;text&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's test it! we call our function and print the result to the output.&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;getTextFromImage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you call your script you should get the following result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~ ❯ node tesseract.js                                                                                                                                                   ⏎
HELLO WORLD!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nice, but it didn't find all the text from our image... &lt;/p&gt;

&lt;p&gt;By default, Tesseract works in &lt;code&gt;SINGLE_BLOCK&lt;/code&gt; mode. A worker instance has a &lt;a href="https://github.com/naptha/tesseract.js/blob/master/docs/api.md#workersetparametersparams-jobid-promise" rel="noopener noreferrer"&gt;setParameters&lt;/a&gt; that let you change Tesseract default behavior. In our case we want to change the &lt;code&gt;tessedit_pageseg_mode&lt;/code&gt; parameter value. Before doing it we need to import the PSM enumeration (this is an acronym for page segmentation mode).&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;createWorker&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="s1"&gt;tesseract.js&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;PSM&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="s1"&gt;tesseract.js/src/constants/PSM.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we call &lt;code&gt;setParameters&lt;/code&gt; method with the wanted mode. For the example, we will use &lt;code&gt;AUTO&lt;/code&gt; mode and let the engine find all lines.&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;// ...&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getTextFromImage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadLanguage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eng&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eng&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setParameters&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;tessedit_pageseg_mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PSM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AUTO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recognize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./hello-world.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;terminate&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;text&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By calling your should get a different result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~ ❯ node tesseract.js                                                                                                                                                   ⏎
HELLO WORLD!

made with € by node-html-to-image
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see it find the whole text. It seems to have difficulties to identify the emoji character but it is a pretty impressive result.&lt;/p&gt;

&lt;p&gt;Here is the final code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createWorker&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="s1"&gt;tesseract.js&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;PSM&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="s1"&gt;tesseract.js/src/constants/PSM.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getTextFromImage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadLanguage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eng&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eng&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setParameters&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;tessedit_pageseg_mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PSM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AUTO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recognize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./hello-world.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;terminate&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;text&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;getTextFromImage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are a lot more &lt;a href="https://github.com/naptha/tesseract.js/blob/master/docs/examples.md" rel="noopener noreferrer"&gt;examples&lt;/a&gt; in Tesseract.js documentation with extra features like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;progress&lt;/li&gt;
&lt;li&gt;multi languages&lt;/li&gt;
&lt;li&gt;whitelist char&lt;/li&gt;
&lt;li&gt;And more...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are curious to see how I tested &lt;a href="https://github.com/frinyvonnick/node-html-to-image" rel="noopener noreferrer"&gt;node-html-to-image&lt;/a&gt;. You can find the source &lt;a href="https://github.com/frinyvonnick/node-html-to-image/blob/master/src/index.spec.js" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You're set 🙌 Hope it will help you!&lt;/p&gt;

&lt;p&gt;Happy Holidays 🎉&lt;/p&gt;




&lt;p&gt;Feedback or ideas are appreciated 🙏 Please tweet me if you have questions &lt;a href="https://twitter.com/YvonnickFrin" rel="noopener noreferrer"&gt;@YvonnickFrin&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>javascript</category>
      <category>node</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Generate images from HTML in Node.js</title>
      <dc:creator>🦁 Yvonnick FRIN</dc:creator>
      <pubDate>Wed, 18 Dec 2019 08:45:35 +0000</pubDate>
      <link>https://dev.to/yvonnickfrin/generate-images-from-html-in-node-js-8p5</link>
      <guid>https://dev.to/yvonnickfrin/generate-images-from-html-in-node-js-8p5</guid>
      <description>&lt;p&gt;As developers, we don't have great skills with image manipulation softwares, but we still need it. In my case I had to generate Twitter cards for social media and flyers for the meetup I co-organize. An important point for use is automation. So I wanted a solution that let me make a template and generates a lot of images without extra work.&lt;/p&gt;

&lt;p&gt;That is why I created &lt;a href="https://github.com/frinyvonnick/node-html-to-image" rel="noopener noreferrer"&gt;node-html-to-image&lt;/a&gt;. A Node.js module that generates images from HTML.&lt;/p&gt;

&lt;p&gt;Here is the simplest example, you provide an output path and a HTML string. That's all!&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;nodeHtmlToImage&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="s1"&gt;node-html-to-image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;nodeHtmlToImage&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./image.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;Hello world!&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The image was created successfully!&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;I talked about automation earlier. It comes with a templating engine, &lt;a href="https://handlebarsjs.com/" rel="noopener noreferrer"&gt;Handlebars&lt;/a&gt;. It enables creating multiple images using the same template.&lt;/p&gt;

&lt;p&gt;In the following example, we changed &lt;code&gt;world&lt;/code&gt; by a placeholder and inject its value with the &lt;code&gt;content&lt;/code&gt; option.&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;nodeHtmlToImage&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="s1"&gt;node-html-to-image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;nodeHtmlToImage&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./image.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;Hello {{name}}!&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;you&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The image was created successfully!&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;You want to generate images from HTML without writing a line of code? No problem, I also made a cli that use &lt;code&gt;node-html-to-image&lt;/code&gt; underneath called &lt;a href="https://github.com/frinyvonnick/node-html-to-image-cli" rel="noopener noreferrer"&gt;node-html-to-image-cli&lt;/a&gt;.&lt;/p&gt;

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

npx node-html-to-image-cli index.html image.png


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

&lt;/div&gt;

&lt;p&gt;Generated image:&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%2Fraw.githubusercontent.com%2Ffrinyvonnick%2Fnode-html-to-image-cli%2Fmaster%2Fmisc%2Fdemo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Ffrinyvonnick%2Fnode-html-to-image-cli%2Fmaster%2Fmisc%2Fdemo.gif" alt="Demonstration of node-html-to-image-cli"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feel free check out the GitHub repositories if you are interested:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/frinyvonnick/node-html-to-image" rel="noopener noreferrer"&gt;node-html-to-image&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/frinyvonnick/node-html-to-image-cli" rel="noopener noreferrer"&gt;node-html-to-image-cli&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Want to support ? Don't forget to leave a ⭐️&lt;/p&gt;




&lt;p&gt;Feedback or ideas are appreciated 🙏 Please tweet me if you have questions &lt;a href="https://twitter.com/YvonnickFrin" rel="noopener noreferrer"&gt;@YvonnickFrin&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>showdev</category>
    </item>
    <item>
      <title>DevTips: Use early returns to avoid nested conditions</title>
      <dc:creator>🦁 Yvonnick FRIN</dc:creator>
      <pubDate>Thu, 12 Dec 2019 12:41:10 +0000</pubDate>
      <link>https://dev.to/yvonnickfrin/devtips-use-early-returns-to-avoid-nested-conditions-4i51</link>
      <guid>https://dev.to/yvonnickfrin/devtips-use-early-returns-to-avoid-nested-conditions-4i51</guid>
      <description>&lt;p&gt;As a developper, you will encounter some patterns you should identify as &lt;a href="https://martinfowler.com/bliki/CodeSmell.html"&gt;code smells&lt;/a&gt;. Most of them have well known solutions. Today I want to talk about using early returns to avoid else statements and nested conditions.&lt;/p&gt;

&lt;p&gt;Let's take a example. I need to call a server to know if a person already exists in my database. The function that makes the call also return a loading indicator so I can inform the user.&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;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;personToLookFor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Thierry&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;doesPersonExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;personToLookFor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;message&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;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;personToLookFor&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; already exists.`&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;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;personToLookFor&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; doesn't exist.`&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;message&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Loading...&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;As you can see the nested conditions and if/else statements are hard to read. You don't really understand what does this piece of code at first glance. I bet you already run into this pattern before. Let's refactor this a bit to make it more maintainable!&lt;/p&gt;

&lt;p&gt;If the call is still pending we can directly quit the function and display the loading indicator.&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;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;personToLookFor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Thierry&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;doesPersonExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;personToLookFor&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;loading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Loading...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;message&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;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;personToLookFor&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; already exists.`&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;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;personToLookFor&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; doesn't exist.`&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;message&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isn't it a bit clearer? We can also get rid of the else statement by returning directly the message in the if statement.&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;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;personToLookFor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Thierry&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;doesPersonExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;personToLookFor&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;loading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Loading...&lt;/span&gt;&lt;span class="dl"&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;result&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;personToLookFor&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; already exists.`&lt;/span&gt; 
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;personToLookFor&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; doesn't exist.`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It also removes the necessity to have a message variable. You're set 🙌&lt;/p&gt;

&lt;p&gt;Hope it will help you!&lt;/p&gt;




&lt;p&gt;Feedback is appreciated 🙏 Please tweet me if you have any questions &lt;a href="https://twitter.com/YvonnickFrin"&gt;@YvonnickFrin&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>tutorial</category>
      <category>codenewbie</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
