<?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: Halo lab</title>
    <description>The latest articles on DEV Community by Halo lab (@halolab).</description>
    <link>https://dev.to/halolab</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F4779%2Fbb61bfc3-aa0c-44ad-beb8-b20a9be61684.png</url>
      <title>DEV Community: Halo lab</title>
      <link>https://dev.to/halolab</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/halolab"/>
    <language>en</language>
    <item>
      <title>How to Run a Python script from Node.js</title>
      <dc:creator>Chuiko Liliia</dc:creator>
      <pubDate>Tue, 14 Mar 2023 11:14:00 +0000</pubDate>
      <link>https://dev.to/halolab/how-to-run-a-python-script-from-nodejs-3f0a</link>
      <guid>https://dev.to/halolab/how-to-run-a-python-script-from-nodejs-3f0a</guid>
      <description>&lt;p&gt;Quite often we hear disputes about what is better to use Node.js or Python. &lt;br&gt;
But what if one day, you come up with a great idea to combine those, for instance to use some Python libraries in your  application, but you just do not have any idea how to integrate it with your Node.js application. Of course you can always build API on top of Python backend(Flack, etc), but in that case you need to build, host and manage one more application, when you just need to run a single Python script. That's why I want to give you step by step instructions on how to achieve this.&lt;/p&gt;

&lt;p&gt;To begin with, let's briefly define what are both languages.&lt;/p&gt;

&lt;p&gt;Node.js is a server-side platform developed on Google Chrome’s Javascript Engine. Node Js allows to develop data-intensive real-time web applications. It is written on JavaScript and allows to run applications on various operating systems such as Windows, Linux, and Mac OS.&lt;/p&gt;

&lt;p&gt;Python is an object-oriented programming language used to create dynamic web applications. The syntax of Python and dynamic typing make it an ideal programming language for scripting.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why you might need to run Python scripts from Node.js
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Node js can't run heavy multitask as it works on a single thread basis, making it difficult for Node Js to execute CPU-bound tasks. Whenever any request is received, the system will complete the request once and only accept the other request. This process slows down the system and ends up in a massive delay.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Python is much more suitable for that back-end applications, that use numerical computations, big data solutions, and machine learning.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Python has one of the largest ecosystems out of any programming community and a lot of open-source libraries. For instance some of built-in AI libraries (Pylearn2, Tensorflow for neural networks, and Scikit-learn for data analysis)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Сall your Python script from Node.js using Child Process module
&lt;/h2&gt;

&lt;p&gt;You will find several libraries that can help you with this issue. As for me, I prefer to use built in &lt;a href="https://nodejs.org/api/child_process.html"&gt;child_process&lt;/a&gt;. The node:child_process module provides the ability to spawn subprocesses. This capability is primarily provided by the child_process.spawn() function.&lt;/p&gt;

&lt;p&gt;First, we need to create a server.js file as the server for our app. Where we suppose that &lt;code&gt;X&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; are large arrays.&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;express&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;express&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="nx"&gt;spawnSync&lt;/span&gt; &lt;span class="p"&gt;}&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;child_process&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="nx"&gt;readFile&lt;/span&gt; &lt;span class="p"&gt;}&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;fs/promises&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="nx"&gt;appendFile&lt;/span&gt; &lt;span class="p"&gt;}&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;fs/promises&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="nx"&gt;join&lt;/span&gt; &lt;span class="p"&gt;}&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;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&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="k"&gt;async&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="nx"&gt;next&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;X&lt;/span&gt; &lt;span class="o"&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;// large array&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="c1"&gt;// large array&lt;/span&gt;

   &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;appendFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`scripts/args.json`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf-8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;w&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pythonProcess&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;spawnSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;python3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
     &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/usr/src/app/scripts/python-script.py&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;first_function&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;/usr/src/app/scripts/args.json&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;/usr/src/app/scripts/results.json&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pythonProcess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()?.&lt;/span&gt;&lt;span class="nx"&gt;trim&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;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pythonProcess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()?.&lt;/span&gt;&lt;span class="nx"&gt;trim&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;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;OK&lt;/span&gt;&lt;span class="dl"&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;status&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;buffer&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;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/usr/src/app/scripts/results.json&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;resultParsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resultParsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server error&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="c1"&gt;//Creates the server on default port 8000 and can be accessed through localhost:8000&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&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="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="s2"&gt;`Server is listening on PORT &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The first parameter, that was passed to the &lt;code&gt;spawnSync&lt;/code&gt; is &lt;code&gt;command&amp;lt;string&amp;gt;&lt;/code&gt;(the command to run, in this case is &lt;code&gt;python3&lt;/code&gt; - the version of python that is required to run your libraries), the second is &lt;code&gt;args &amp;lt;string[]&amp;gt;&lt;/code&gt;(list of string arguments). You can also pass the third parameter &lt;code&gt;options&lt;/code&gt;, the more detailed information can be found by the &lt;a href="https://nodejs.org/api/child_process.html#child_processspawnsynccommand-args-options"&gt;link&lt;/a&gt;.&lt;br&gt;
I propose to consider in more detail the list I am passing as the second argument&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;'/usr/src/app/scripts/python-script.py' - is the path of the script I need to execute&lt;/li&gt;
&lt;li&gt;'first_function' - is the name of the function I want to run inside that file&lt;/li&gt;
&lt;li&gt;'/usr/src/app/scripts/args.json' - is the path to the file with arguments to this function. Actually you can directly pass those arguments  using &lt;code&gt;JSON.stringify()&lt;/code&gt; function in Node.js, but as for me  it's better to write those arguments down into the file and then read that from Python script. One of the reasons is that you might need to pass as arguments large arrays of data and this will cause errors.&lt;/li&gt;
&lt;li&gt;'/usr/src/app/scripts/results.json' - is the path, where I want my Python script to write results, after it is finished, so I can read that from node.js.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Passed arguments can be found in &lt;code&gt;sys.argv&lt;/code&gt; array in Python script. The &lt;code&gt;sys.argv&lt;/code&gt; list is a list that contains command line arguments in a python program. Whenever we run a python program from a command line interface, we can pass different arguments to the program. The program stores all the arguments and the file name of the python file in the sys.argv list. This can be seen in more detail by writing a simple example script&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;first_function&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;json_obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json_obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;calculatedResults&lt;/span&gt; &lt;span class="o"&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# it is just example of data to return, in fact you will calculate it bellow
&lt;/span&gt;    &lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"X"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"y"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="c1"&gt;# do some your calculations based on X and y and put the result to the calculatedResults
&lt;/span&gt;    &lt;span class="c1"&gt;# print(make_pipeline)
&lt;/span&gt;    &lt;span class="n"&gt;json_object_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;calculatedResults&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="s"&gt;"w"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;outfile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;outfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json_object_result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"OK"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&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="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'first_function'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;first_function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;In two words, in Node.js script we write down to the file all required arguments, run &lt;code&gt;spawnSync&lt;/code&gt; passing list of arguments and after Python script reads passed arguments from the file, makes all calculations and writes down to the file all results. At the moments all this results can be read in Node.js from file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run Python script, that uses specific Python libraries
&lt;/h2&gt;

&lt;p&gt;One of the main goals is to have ability to use built-in AI or other libraries. It's always not a good idea to install dependencies and libraries globally in a system, it can lead to version conflicts, deployment difficulties, and problems with multiple developers working on a project at the same time, for example. That's why the perfect way is to use Docker. You can build the image yourself, but the easiest solution is to use an existing one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;nikolaik/python-nodejs:latest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;development&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/src/app&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;scikit-learn numpy pandas simplejson
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./package.json ./yarn.lock ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;yarn
&lt;span class="k"&gt;RUN &lt;/span&gt;yarn &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./ ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;yarn build
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PORT 4000&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; $PORT&lt;/span&gt;


&lt;span class="c"&gt;# Production mode&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;nikolaik/python-nodejs:latest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;production&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;scikit-learn numpy pandas simplejson
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; NODE_ENV=production&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; NODE_ENV=${NODE_ENV}&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/src/app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=development /usr/src/app ./&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PORT 4000&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; $PORT&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "dist/main"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For now we can use &lt;code&gt;scikit-learn&lt;/code&gt;, &lt;code&gt;numpy&lt;/code&gt;, &lt;code&gt;pandas&lt;/code&gt; and &lt;code&gt;simplejson&lt;/code&gt; libraries on Python script, as they are available in the created docker container.&lt;/p&gt;

&lt;p&gt;By following the steps above, you can create a new process and execute a Python script from your Node.js application. This can be useful in cases where you need to integrate Python code into your Node.js application or when you need to perform certain tasks that are better suited for Python. Described simple app can be downloaded from the &lt;a href="https://github.com/liliya-dev/python-scripts-node.js"&gt;Github&lt;/a&gt;, there you can also find instructions how to run it.&lt;/p&gt;

&lt;p&gt;Happy coding and wish you to have a nice day!&lt;/p&gt;

</description>
      <category>python</category>
      <category>node</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Implementing a grid system using a simple hand-written single-pass compiler in Sass</title>
      <dc:creator>Kapelianovych Yevhen</dc:creator>
      <pubDate>Sun, 16 Jan 2022 09:12:46 +0000</pubDate>
      <link>https://dev.to/halolab/implementing-a-grid-system-using-a-simple-hand-written-single-pass-compiler-in-sass-2h19</link>
      <guid>https://dev.to/halolab/implementing-a-grid-system-using-a-simple-hand-written-single-pass-compiler-in-sass-2h19</guid>
      <description>&lt;p&gt;What’s the first thing that pops up in your mind when you think about Sass? Yes, it is the powerful CSS preprocessor that is widely used now. You may also say that it has convenient features for encapsulating repeated parts of the CSS or some complex cases. You might mention nesting, placeholders, etc. But Sass is more powerful than that because it has SassScript.&lt;/p&gt;

&lt;p&gt;So, what is this? &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SassScript&lt;/strong&gt; is a set of extensions that can be included in the Sass documents to compute variables from property values and uses properties of variables, arithmetic, and other functions. That gives us the ability to organize a code into functions, perform conditional operations, and many more. Actually, these two abilities are enough to build a whole program.&lt;/p&gt;

&lt;p&gt;So, let’s start.&lt;/p&gt;

&lt;p&gt;Typical parser implementations theory defines using a character reader, which is used by a lexer that produces tokens, and the last one is the parser itself which creates the AST.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--f8-wDVfx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/avhs345908nmyub7kulk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--f8-wDVfx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/avhs345908nmyub7kulk.png" alt="Parts of a typical parser" width="880" height="71"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will build a less capable compiler because Sass has some limitations. Sass cannot work with a filesystem in any way. Because of that, we cannot store custom syntax in separate files. So we should write it inside Sass files. Also, it is inconvenient to process a character's stream because Sass does not provide the most valuable methods for working with strings (and it does not have streams at all). The same goes for the lexer. But we can simulate the latter if we assume that all keywords are already tokens. Sass has a &lt;code&gt;list&lt;/code&gt; structure where a space can be a separator between items. And there is a &lt;code&gt;sass:list&lt;/code&gt; module that provides some functions to work with lists. We are going to use that ability to simulate the lexer skipping the character sequence stream at all. All the code we are going to write as an argument to a &lt;code&gt;value&lt;/code&gt; function. And despite the length of the words, it will still be the list!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nt"&gt;value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;sequence&lt;/span&gt; &lt;span class="nt"&gt;of&lt;/span&gt; &lt;span class="nt"&gt;the&lt;/span&gt; &lt;span class="nt"&gt;tokens&lt;/span&gt;&lt;span class="o"&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 me describe the idea.&lt;/p&gt;

&lt;p&gt;We plan to create a simple responsive grid system. For that, we will assume that there is a table with 64 columns (there may be more or less, it depends) which covers a whole page. Each cell of the table is a square figure. It gives us responsiveness because, on mobile phones, cells will have a smaller size than on laptops. Based on that, we receive a dynamic value (one side of the cell) that we use to express all dimensions in our grid.&lt;/p&gt;

&lt;p&gt;You may want to use &lt;em&gt;rem&lt;/em&gt; or &lt;em&gt;vw&lt;/em&gt; for that purpose. And that’s okay. It’s up to you how to define a unit value.&lt;br&gt;
With that, we’ll be able to say, for example, that “this block should have a width of 5 columns“, and blocks will resize according to unit value changes.&lt;/p&gt;

&lt;p&gt;Okay, let’s jump into the code now.&lt;/p&gt;

&lt;p&gt;The simplest thing is to calculate the unit value. We know that the grid will have 64 columns. So, the width of one cell can be defined like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="k"&gt;@use&lt;/span&gt; &lt;span class="s1"&gt;'sass:math'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="na"&gt;:root&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;-&lt;/span&gt;&lt;span class="err"&gt;—&lt;/span&gt;&lt;span class="na"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100vw&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Later, I won’t write imports of standard Sass’s modules for brevity. Assume that they are present already.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We took a benefit from CSS variables here and made it global. That will allow us to access this value everywhere in the runtime. We can place it into the mixin named &lt;code&gt;init&lt;/code&gt; to allow the developer to override the columns count.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@mixin&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$columns&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="err"&gt;—&lt;/span&gt;&lt;span class="na"&gt;-unit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100vw&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$columns&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Also, you can define lower and upper bounds for the unit value by using &lt;strong&gt;clamp&lt;/strong&gt; CSS function, but we won’t do that to simplify the code examples.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Move on to the syntax. We're expecting our grid will work for the following use-cases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nt"&gt;value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;8&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Just the columns count&lt;/span&gt;
&lt;span class="nt"&gt;value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;from&lt;/span&gt; &lt;span class="nt"&gt;6&lt;/span&gt; &lt;span class="nt"&gt;to&lt;/span&gt; &lt;span class="nt"&gt;21&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// A distance from 6th column to the 21th column&lt;/span&gt;
&lt;span class="nt"&gt;value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;8&lt;/span&gt; &lt;span class="nt"&gt;min&lt;/span&gt; &lt;span class="nt"&gt;20px&lt;/span&gt; &lt;span class="nt"&gt;max&lt;/span&gt; &lt;span class="nt"&gt;70px&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// The columns count with the lower and upper bounds of the result value&lt;/span&gt;
&lt;span class="nt"&gt;value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;from&lt;/span&gt; &lt;span class="nt"&gt;6&lt;/span&gt; &lt;span class="nt"&gt;to&lt;/span&gt; &lt;span class="nt"&gt;21&lt;/span&gt; &lt;span class="nt"&gt;min&lt;/span&gt; &lt;span class="nt"&gt;20px&lt;/span&gt; &lt;span class="nt"&gt;max&lt;/span&gt; &lt;span class="nt"&gt;70px&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// The same but with a range between columns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have defined the two blocks of the expression: &lt;em&gt;dimension&lt;/em&gt; and &lt;em&gt;bounds&lt;/em&gt;. The latter is optional. Let’s dive deep into the dimension block a little bit.&lt;/p&gt;

&lt;p&gt;The simplest case is when it equals the number - the columns count (see above). There is no more to discuss. The next variant is more difficult. It includes two mandatory keywords: &lt;code&gt;from&lt;/code&gt; and &lt;code&gt;to&lt;/code&gt;, and two interchangeable: &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;end&lt;/code&gt;. The last two keywords equal to the 0 and 64 (or whatever number you decided to use) accordingly: &lt;code&gt;from start to end&lt;/code&gt;. That expression is equal to &lt;code&gt;from 0 to 64&lt;/code&gt; or &lt;code&gt;100vw&lt;/code&gt;.&lt;br&gt;
The next block has only one variant: &lt;code&gt;min &amp;lt;number with unit&amp;gt; max &amp;lt;number with unit&amp;gt;&lt;/code&gt;. As numbers, you can use whatever value you want: pixels, rems, percentages, and so on.&lt;/p&gt;

&lt;p&gt;That’s all. Now, when we have all rules defined, we shall go to the most exciting part - the code.&lt;/p&gt;

&lt;p&gt;I already said that we would operate on the list of tokens, and for that purpose, we will use the &lt;em&gt;list&lt;/em&gt; structure. Unfortunately, there are not enough methods to work with lists in SassScript. So, let’s implement missing ones.&lt;br&gt;
Firstly, we need the &lt;code&gt;isEmpty&lt;/code&gt; function to determine whether a list has tokens or not.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@function&lt;/span&gt; &lt;span class="nf"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$list&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="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&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;That function is pretty straightforward and does not require additional explanation.&lt;/p&gt;

&lt;p&gt;Along with that, we should be able to remove processed tokens from the list. For that, we are going to implement a generic &lt;code&gt;slice&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@function&lt;/span&gt; &lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$list&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$from&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$to&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$_separator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;separator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$list&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;@for&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="ow"&gt;from&lt;/span&gt; &lt;span class="nv"&gt;$from&lt;/span&gt; &lt;span class="ow"&gt;to&lt;/span&gt; &lt;span class="nv"&gt;$to&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$list&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$_separator&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="nv"&gt;$_copy&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;blockquote&gt;
&lt;p&gt;Fun fact: all functions that are implemented in SassScript are pure.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It reminds the code from JavaScript with the difference that the first index of the list is 1, unlike 0 in JavaScript. Also, we should preserve a separator of an original list to the sliced, and that’s all.&lt;/p&gt;

&lt;p&gt;With that, we can start writing our main &lt;code&gt;value&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@function&lt;/span&gt; &lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$tokens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$tokens&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nv"&gt;$_numbers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nv"&gt;$_borders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;@if&lt;/span&gt; &lt;span class="nf"&gt;isNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$_numbers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;@else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$_numbers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;@if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$_borders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;borders&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;borders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;@if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_borders&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="nf"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_borders&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_numbers&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_numbers&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_borders&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&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="nf"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_numbers&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_numbers&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&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 stop here. That is a huge function. Because the syntax is tiny and unambiguous, we can rely on the order of tokens. We know that first is the dimension block, and the second is the borders block. The first &lt;code&gt;if/else&lt;/code&gt; block has the code for parsing tokens of the dimension block. Also, you saw &lt;code&gt;$_numbers&lt;/code&gt; and &lt;code&gt;$_borders&lt;/code&gt; variables. We could define them later, but it is better to define them with a default value to avoid possible errors while using it.&lt;/p&gt;

&lt;p&gt;You may notice that there are unknown functions: &lt;code&gt;isNumber&lt;/code&gt;, &lt;code&gt;number&lt;/code&gt; and &lt;code&gt;range&lt;/code&gt;. Let’s define them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@function&lt;/span&gt; &lt;span class="nf"&gt;isNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&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="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;type-of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"number"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@function&lt;/span&gt; &lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$list&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;@if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;@error&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$_value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is not a number!"&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="nv"&gt;$_value&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;isNumber&lt;/code&gt;, as it states from the name, checks if the value has a number type. &lt;code&gt;number&lt;/code&gt; function takes a first token from the list and makes sure that it is a valid number.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;range&lt;/code&gt; function is a bit complex.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@function&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$list&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nv"&gt;$leftNumber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;toNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nv"&gt;$rightNumber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;toNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="k"&gt;@if&lt;/span&gt; &lt;span class="nv"&gt;$leftNumber&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$rightNumber&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;@error&lt;/span&gt; &lt;span class="s1"&gt;'From number cannot be greater than To'&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="nv"&gt;$leftNumber&lt;/span&gt; &lt;span class="nv"&gt;$rightNumber&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simply put, this function reads tokens and checks if they are valid. There are yet other functions that we should provide: &lt;code&gt;skip&lt;/code&gt; and &lt;code&gt;toNumber&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@function&lt;/span&gt; &lt;span class="nf"&gt;toNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@if&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;keywords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$start&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;@return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;@if&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;@return&lt;/span&gt; &lt;span class="n"&gt;unit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$columns&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;@if&lt;/span&gt; &lt;span class="nf"&gt;isNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&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="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;@error&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt; is not a number or "&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;keywords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$start&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;"/"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;keywords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$end&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;" keywords.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@function&lt;/span&gt; &lt;span class="nf"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$word&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@if&lt;/span&gt; &lt;span class="nv"&gt;$word&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$list&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;@error&lt;/span&gt; &lt;span class="s1"&gt;'Word &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$word&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt; does not match the &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$list&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt; sequence.'&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="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$list&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&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;toNumber&lt;/code&gt; function is needed to convert &lt;em&gt;start&lt;/em&gt; and &lt;em&gt;end&lt;/em&gt; keywords to corresponding numbers and check whether the starting column’s value is lower than the ending column’s value. &lt;code&gt;skip&lt;/code&gt; is just a convenient method to skip the first token in the list.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;range&lt;/code&gt; should return starting and ending column numbers to the &lt;code&gt;value&lt;/code&gt; to calculate an actual value.&lt;br&gt;
Okay, the dimension block is ready. The borders block remains only.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@function&lt;/span&gt; &lt;span class="nf"&gt;borders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$tokens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$tokens&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nv"&gt;$_min&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nv"&gt;$_max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$_min&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nv"&gt;$_min&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nv"&gt;$_max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_copy&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;@return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_min&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$_max&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here the logic is the same as in the &lt;code&gt;range&lt;/code&gt; function. At that point, we have a complete tiny compiler though it looks somewhat different than typical implementations. But the primary goal of this article is to show that Sass is much more powerful than it seems, and even though CSS gets many features that Sass has, the latter is still in demand.&lt;/p&gt;

&lt;p&gt;Now, we can use our super compiler to write dimensions in the 64 columns' system.&lt;br&gt;
The example of the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@use&lt;/span&gt; &lt;span class="s1"&gt;'grid'&lt;/span&gt; &lt;span class="nt"&gt;as&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;.some-element&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;margin-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;tomato&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.some-other-element&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="m"&gt;16&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;margin-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;tomato&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;That gives us simpler management of an element’s position. Thus it can be used as a simple replacement for the common grid systems. Also, it can help you to be closer to design because designers use similar grids to combine elements into the whole page.&lt;/p&gt;

&lt;p&gt;Personally, it reminds me of a mix of &lt;a href="https://getbootstrap.com"&gt;Bootstrap&lt;/a&gt; and &lt;a href="https://www.oddbird.net/susy/"&gt;Susy&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KrwTyc-F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/902ndruy5ppwvnq8dq4s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KrwTyc-F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/902ndruy5ppwvnq8dq4s.png" alt="A grasp of a grid" width="880" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The further development of that idea you can see &lt;a href="https://github.com/Halo-Lab/jessie"&gt;here&lt;/a&gt;. There is &lt;a href="https://halo-lab.github.io/jessie/"&gt;an example page&lt;/a&gt; that shows simple elements positioning inside the grid. We implemented that idea on &lt;a href="https://halo-lab.com"&gt;our site&lt;/a&gt;, that's why we can say it works and works well.&lt;/p&gt;

&lt;p&gt;Thank you for reading, and have fun!&lt;/p&gt;

</description>
      <category>sass</category>
      <category>compiler</category>
      <category>grid</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Part 2. Quick guide to make your Azure applications work.</title>
      <dc:creator>Chuiko Liliia</dc:creator>
      <pubDate>Wed, 05 Jan 2022 12:58:11 +0000</pubDate>
      <link>https://dev.to/halolab/part-2-quick-guide-to-make-your-azure-applications-work-gd1</link>
      <guid>https://dev.to/halolab/part-2-quick-guide-to-make-your-azure-applications-work-gd1</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In the previous article, we have already created an Azure App service instance. And now you are able to see the Microsoft Azure default page by the link. This time we are going to migrate Strapi app, Next.js app and Mongo DB to Azure. &lt;/p&gt;

&lt;h2&gt;
  
  
  Preparing Azure App Services for the Migration process
&lt;/h2&gt;

&lt;p&gt;Your project probably has specific environment variables. They should be added to Azure.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Go to the Azure App service instance, find the Configuration in the Settings tab, select Application Settings section.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Here are two kinds of it. Application Settings and Connection Strings. There is only one case for using strings instead of settings, more detailed information can be found by the &lt;a href="https://docs.microsoft.com/en-us/azure/app-service/configure-common" rel="noopener noreferrer"&gt;link&lt;/a&gt;. Use Application settings and click on &lt;em&gt;&lt;strong&gt;+New application setting&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Put the name and value of the variable and select if it is a deployment slot setting. With this setting in place, database connection strings and other settings are not swapped when the slots are swapped. So the staging slot will always point to the staging database, and the production slot will always point to the production database.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg0oj5jkik3yx6bx1fdz6.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg0oj5jkik3yx6bx1fdz6.jpeg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Keep in mind that the values you set in App Service override the values in Web.config and others.&lt;/p&gt;

&lt;p&gt;Later I will talk about different deployment methods. But no matter which one you choose, you need to know that deploying new code directly to the production application is a bad practice. For this purpose, every App service instance has staging slots. Deploying your application to a non-production slot has the following benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can validate app changes in a staging deployment slot before swapping it with the production slot.&lt;/li&gt;
&lt;li&gt;Deploying an app to a slot first and swapping it into production guarantees that all instances of the slot are warmed up before being swapped into production. This eliminates downtime when you deploy your app. The traffic redirection is seamless, and no requests are dropped because of swap operations. You can automate this entire workflow by configuring autoswap when pre-swap validation isn't needed.&lt;/li&gt;
&lt;li&gt;After a swap, the slot with the previously staged app now has the previous production app. If the changes swapped into the production slot aren't as you expect, you can perform the same swap immediately to get your "last known good site" back.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the best idea is to create a preview slot that will not affect the production. Creating the slot for an app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to Azure App service instance, find the deployment slots in the Deployment tab, click on &lt;strong&gt;&lt;em&gt;Add slot&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Put the slot name. It will take your main slot root domain name + name that you will write.&lt;/li&gt;
&lt;li&gt;After that, you can select if you need to clone all settings from the main slot or not. If you clone settings, it will make the full copy of the existing slot with the same environment variables. So if you want to use another database or change other settings, you shouldn't clone settings or change them manually after the new slot is ready.&lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6smg4u4ja5qy97nqdipx.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6smg4u4ja5qy97nqdipx.jpeg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In a few minutes, the preview slot will be available by its own url and can be found in the Deployment Slots tab of the Azure App service instance.  And we can proceed to deploy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the deployment way
&lt;/h2&gt;

&lt;p&gt;There are a few options to move your project to the instance. Most popular are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can deploy to Azure App Service as part of your continuous deployment (CD) workflows via GitHub, Azure Repos&lt;/li&gt;
&lt;li&gt;Try Azure Repos with Azure App, make sure you have already created an Azure DevOps Organization to store your project files.&lt;/li&gt;
&lt;li&gt;Or use the Azure App Service extension for VS Code to create quickly, manage, and deploy your websites. Just press the &lt;strong&gt;&lt;em&gt;install button&lt;/em&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbct94qnzxfnswjqh74pn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbct94qnzxfnswjqh74pn.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The simplest way for me is deploying via VScode. You will be able to create and deploy resources with it. But this method has a list of disadvantages for my purposes and for. Probably this deployment way will be described in my other article, and for now, deploying using workflows via GitHub was chosen for my project. &lt;/p&gt;

&lt;h2&gt;
  
  
  Steps to deploy my Strapi back-end application (or any other node.js app) to Azure via GitHub:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Certainly, to achieve this target, your app should be connected to the remote git repository. &lt;/li&gt;
&lt;li&gt;Go to your project and create the &lt;em&gt;.github&lt;/em&gt; folder at the root of it.&lt;/li&gt;
&lt;li&gt;In the &lt;em&gt;.github&lt;/em&gt; folder create &lt;em&gt;workflows&lt;/em&gt; folder.&lt;/li&gt;
&lt;li&gt;In &lt;em&gt;workflows&lt;/em&gt; folder create the file  with the following name scheme 
&lt;em&gt;branch_name_app_name(slot_name).yml&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;For example:
App-name: ‘production-app’
Branch from which you want deploy: master
Slot: ‘preview’
Final name of the file: master_production-app(preview).yml&lt;/li&gt;
&lt;li&gt;Now configure the created &lt;em&gt;.yml&lt;/em&gt; file with the following settings. Here is an example that uses the above-declared names:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  push:
    branches:
      - master
  pull_request:
    branches:
      - master

env:
  AZURE_WEBAPP_NAME: production-app  # set this to your application's name
  AZURE_WEBAPP_PACKAGE_PATH: "."      # set this to the path to your web app project, defaults to the repository root
  NODE_VERSION: '14.x'                # set this to the node version to use
  API_URL: "https://production-app.azurewebsites.net" # main slot url

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@master
    - name: Set Node.js version
      uses: actions/setup-node@v1
      with:
        node-version: '14.x'

    # install dependencies, build, and test
    - name: npm install, build, and test  #describes which commands need to be run
      run: |
        npm install
        npm run build --if-present
        npm run test --if-present

    - uses: azure/webapps-deploy@v2
      with:
        app-name: 'production-app’'
        slot-name: 'preview'
        publish-profile: ${{ secrets.AzureAppService_PublishProfile_PRODUCTION }}
        package: .

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;In the file, all seems to be clear. The only exception is some odd variable used on the penultimate line of code. This setting is required to secure your deployments. Reproduce the following steps to get the value :&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;a.&lt;/strong&gt; Go to your preview slot instance and select Get Publish Profile. The file will be downloaded. Open it with the notepad or use your imagination.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3trnoqh02xwzbv2jugy.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3trnoqh02xwzbv2jugy.jpeg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;b.&lt;/strong&gt; Copy all content of the opened file.&lt;br&gt;
&lt;strong&gt;c.&lt;/strong&gt; Go to your repository on GitHub -&amp;gt; Settings -&amp;gt; Secrets and press &lt;strong&gt;&lt;em&gt;New Repository Secret button&lt;/em&gt;&lt;/strong&gt;.&lt;br&gt;
&lt;strong&gt;d.&lt;/strong&gt; Add name &lt;em&gt;AZUREAPPSERVICE_PUBLISHPROFILE_PRODUCTION&lt;/em&gt; in value input, paste the copied content from the file and save changes. In two words, this variable connects your repo with the application instance on Azure.&lt;/p&gt;

&lt;p&gt;So, when this thousandth step is complete, you can finally push your code to GitHub by directly pushing or creating a pull request to master-branch. Now it is time to take a cup of tea and just follow the action with full deployment logs on GitHub in Actions tab. It may take some time…&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6om0667eejx6da84en26.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6om0667eejx6da84en26.jpeg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What happens now? First of all, GitHub sets the node.js version, installs all dependencies from package.json, and runs the build command. If there are no errors during building, it zips all the files without the node-modules folder and passes them to Azure. Azure does the same steps: extracts files, installs node modules, creates the production build, then removes the previous project folder and instead puts the new one. After it starts the new Docker container and it is warmed up, it runs the npm start command and starts the app.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq9ne1dol03wx3k2taqay.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq9ne1dol03wx3k2taqay.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Don’t be nervous while waiting. The action can take up to 10 minutes or even more for the first time deploying. When the action is completed, you can visit the link of the preview slot. If you are lucky, you will see your app working. But don’t forget the main Microsoft concept: Microsoft — Just restart it. Check if everything works, and then proceed to swap the app to the production slot. To do this, go to the production Azure App service to Deployment slots, find and press the &lt;em&gt;&lt;strong&gt;swap button&lt;/strong&gt;&lt;/em&gt;. Select which slot to swap and to which, confirm the action and wait about 5 minutes. When the swap process is ready, you will get the message. And now all your changes are available on the production slot, and the preview slot link should lead you to the example Microsoft Page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Steps to deploy my Next.js application to Azure via GitHub.
&lt;/h2&gt;

&lt;p&gt;Actually, the steps to deploy next.js are almost the same as for Node.js application. There are some small distinctions. Next.js project doesn’t have the obvious server.js file that is required to deploy it to Azure App Service. There is also another way: deploy to Static Web App Azure service. But it also can’t be used in a simple way because Next.js has the server-side part, which leads to difficulties with deploying it as the static app. So here is what we should do to deploy Next.js app to Azure App Service, besides what we have already done for the previous app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the root project folder create &lt;em&gt;server.js&lt;/em&gt; file with the next content and install all missing dependencies:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { createServer } = require("http");
const next = require("next");

const port = process.env.PORT || 3000;
const app = next({ dev: false });
const handle = app.getRequestHandler();

app.prepare().then(() =&amp;gt; {
  createServer((req, res) =&amp;gt; {
    handle(req, res); 
  }).listen(port, (err) =&amp;gt; {
    if (err) throw err;
    console.log(`&amp;gt; Ready on http://localhost:${port}`);
  });
});

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Change your &lt;strong&gt;start&lt;/strong&gt; script in the &lt;em&gt;package.json&lt;/em&gt; file to “node server”.&lt;/li&gt;
&lt;li&gt;In the projects root create &lt;em&gt;web.config&lt;/em&gt; file with the code:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;
&amp;lt;!--
     This configuration file is required if iisnode is used to run node processes behind
     IIS or IIS Express.  For more information, visit:
     https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/web.config
--&amp;gt;

&amp;lt;configuration&amp;gt;
  &amp;lt;system.webServer&amp;gt;
    &amp;lt;!-- Visit http://blogs.msdn.com/b/windowsazure/archive/2013/11/14/introduction-to-websockets-on-windows-azure-web-sites.aspx for more information on WebSocket support --&amp;gt;
    &amp;lt;webSocket enabled="false" /&amp;gt;
    &amp;lt;handlers&amp;gt;
      &amp;lt;!-- Indicates that the server.js file is a node.js site to be handled by the iisnode module --&amp;gt;
      &amp;lt;add name="iisnode" path="server.js" verb="*" modules="iisnode"/&amp;gt;
    &amp;lt;/handlers&amp;gt;
    &amp;lt;rewrite&amp;gt;
      &amp;lt;rules&amp;gt;
        &amp;lt;!-- Do not interfere with requests for node-inspector debugging --&amp;gt;
        &amp;lt;rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true"&amp;gt;
          &amp;lt;match url="^server.js\/debug[\/]?" /&amp;gt;
        &amp;lt;/rule&amp;gt;

        &amp;lt;!-- First we consider whether the incoming URL matches a physical file in the /public folder --&amp;gt;
        &amp;lt;rule name="StaticContent"&amp;gt;
          &amp;lt;action type="Rewrite" url="public{REQUEST_URI}"/&amp;gt;
        &amp;lt;/rule&amp;gt;

        &amp;lt;!-- All other URLs are mapped to the node.js site entry point --&amp;gt;
        &amp;lt;rule name="DynamicContent"&amp;gt;
          &amp;lt;conditions&amp;gt;
            &amp;lt;add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/&amp;gt;
          &amp;lt;/conditions&amp;gt;
          &amp;lt;action type="Rewrite" url="server.js"/&amp;gt;
        &amp;lt;/rule&amp;gt;
      &amp;lt;/rules&amp;gt;
    &amp;lt;/rewrite&amp;gt;

    &amp;lt;!-- 'bin' directory has no special meaning in node.js and apps can be placed in it --&amp;gt;
    &amp;lt;security&amp;gt;
      &amp;lt;requestFiltering&amp;gt;
        &amp;lt;hiddenSegments&amp;gt;
          &amp;lt;remove segment="bin"/&amp;gt;
        &amp;lt;/hiddenSegments&amp;gt;
      &amp;lt;/requestFiltering&amp;gt;
    &amp;lt;/security&amp;gt;

    &amp;lt;!-- Make sure error responses are left untouched --&amp;gt;
    &amp;lt;httpErrors existingResponse="PassThrough" /&amp;gt;

    &amp;lt;!--
      You can control how Node is hosted within IIS using the following options:
        * watchedFiles: semi-colon separated list of files that will be watched for changes to restart the server
        * node_env: will be propagated to node as NODE_ENV environment variable
        * debuggingEnabled - controls whether the built-in debugger is enabled
      See https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/web.config for a full list of options
    --&amp;gt;
    &amp;lt;iisnode watchedFiles="web.config;*.js"/&amp;gt;
  &amp;lt;/system.webServer&amp;gt;
&amp;lt;/configuration&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Reproduce all steps for deploying node.js app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Congrats! Deploying both front-end and back-end applications is finally finished. The last thing we need to migrate is the Mongo database.&lt;/p&gt;

&lt;p&gt;The first and main thing you should know before starting the migration database to &lt;strong&gt;Azure Cosmos DB&lt;/strong&gt; for &lt;strong&gt;Mongo&lt;/strong&gt; – don’t ever do this!!! &lt;strong&gt;Strapi&lt;/strong&gt; and &lt;strong&gt;Azure Cosmos DB for Mongo&lt;/strong&gt; are almost incompatible. Actually, I still don’t understand what Azure Cosmos for Mongo is compatible with. &lt;/p&gt;

&lt;p&gt;It doesn’t support a lot of operators and expressions that Strapi uses. For example: &lt;strong&gt;&lt;em&gt;$let&lt;/em&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;em&gt;$where&lt;/em&gt;&lt;/strong&gt;, &lt;em&gt;&lt;strong&gt;$meta&lt;/strong&gt;&lt;/em&gt; and others. I have made a migration and faced indexing problems and a lot of unsupported operators. After a huge amount of work was done and after most of the problems were fixed, it finally started to work together. But when I updated the Strapi to the new version, I got one thousand additional problems. And finally, official representatives of the company Strapi gave me the answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Technically CosmosDB is not entirely MongoDB (even with the API implemented) It's not on the list of supported databases, and may not fully work with the ORM being used (mongoose).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Moreover, it has a complicated way to take backups. The system takes snapshots, but you can't get them immediately. Firstly you need to create a support request for the Microsoft Support team. It can be done manually in 2 minutes in Mongo Atlas. Just select the required snapshot and click the &lt;strong&gt;&lt;em&gt;restore button&lt;/em&gt;&lt;/strong&gt;. Looks much simpler, doesn't it?&lt;/p&gt;

&lt;p&gt;Don't waste time fixing problems, there is an easy way to avoid them. If your target is just to speed up the application, use Mongo Atlas for hosting the database and select the Azure cloud provider and the region closest to your customers. In case you need more options for regions, backup settings and some other benefits, learn about dedicated cluster tier features.&lt;/p&gt;

&lt;p&gt;If Mongo Atlas cluster is hosted on Azure servers, most of the requests will not go over the public network, they will use the Azure backbone network instead. Which is more secure and the fastest way to deliver the data.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdoio4zdi4f48h2dpfwo0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdoio4zdi4f48h2dpfwo0.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the end, we have two applications moved to Azure and Mongo DB hosted on the Mongo Atlas. It is the optimal solution for my purposes. But be ready to read more about Azure, believe me, you will definitely need it.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>nextjs</category>
      <category>mongodb</category>
      <category>node</category>
    </item>
    <item>
      <title>From zero to one. How to Deploy your MongoDB, Node, Strapi, NextJS app to Microsoft Azure.</title>
      <dc:creator>Chuiko Liliia</dc:creator>
      <pubDate>Wed, 29 Dec 2021 15:18:26 +0000</pubDate>
      <link>https://dev.to/halolab/from-zero-to-one-how-to-deploy-your-mongodb-node-strapi-nextjs-app-to-microsoft-azure-4c7g</link>
      <guid>https://dev.to/halolab/from-zero-to-one-how-to-deploy-your-mongodb-node-strapi-nextjs-app-to-microsoft-azure-4c7g</guid>
      <description>&lt;h2&gt;
  
  
  Part 1. Introduction and creating all required for migration resources.
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hi to everyone! This article will be helpful if you have little or no knowledge of cloud technologies.&lt;/p&gt;

&lt;p&gt;There are three main cloud providers: Google Cloud, AWS and Azure. Let’s imagine that your task is to move the application to Azure.&lt;/p&gt;

&lt;p&gt;Before continuing, note that the best way to familiarize with basic Azure cloud features, to gain a foundational knowledge of cloud services, and the way those services are provided with Microsoft Azure is to learn and pass &lt;strong&gt;&lt;em&gt;Exam AZ-900: Microsoft Azure Fundamentals&lt;/em&gt;&lt;/strong&gt;. The exam is for candidates who are just beginning to work with cloud-based solutions and services or are new to Azure. Azure Fundamentals can be used to prepare for other Azure role-based or specialty certifications, but it is not a prerequisite for any of them. All Microsoft Azure learning has two options: online, which is always free, and instructor-led, which is paid. Passing the exam and getting the certification is always paid. The price depends on the country. One more tip: learn it before migration because learning during the process is a bad idea. There is much to say about passing Microsoft exams, but I suggest we move on to the next step and explore the project structure. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project structure and reasons for migration to Azure&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So, let’s do a deep dive into the project structure before moving on.&lt;/p&gt;

&lt;p&gt;Front-end: NEXT.js app, hosted on Vercel.&lt;br&gt;
Back end: Strapi CMS + custom node scripts, hosted on Heroku&lt;br&gt;
DB: Mongo db hosted on Mongo Atlas&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The common problems with current providers include:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;  No simple ways to spread application to multiply regions and elastically scale the capacity based on demand.&lt;/li&gt;
&lt;li&gt;  No static inbound and outbound IP addresses (only via proxy), which I needed to secure back-end and DB connections.&lt;/li&gt;
&lt;li&gt;  No obvious ways to give separate accesses to resources, based on roles.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;First steps to start to work with Azure, regardless wich computing services you choose to host applications&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Firstly go to &lt;a href="https://azure.microsoft.com/" rel="noopener noreferrer"&gt;Microsoft Azure Portal&lt;/a&gt; and create the account. After you complete the registration, you will have a single tenant ID associated with your account, which will not change unless you ask Microsoft to delete your account. &lt;strong&gt;&lt;em&gt;Tenant&lt;/em&gt;&lt;/strong&gt; is associated with a single identity (person, company, or organization) and can own one or several &lt;strong&gt;&lt;em&gt;subscriptions&lt;/em&gt;&lt;/strong&gt;. At this step you will only have one subscription. An Azure subscription is a logical container used to provision resources in Azure. It holds the details of all your resources like virtual machines (VMs), databases, and more. When you create an Azure resource like a VM, you identify the subscription it belongs to. A subscription is linked to a payment setup and each subscription will result in a separate bill and can use different payment methods. Resources from one subscription are isolated from resources in other subscriptions.&lt;/p&gt;

&lt;p&gt;During the registration in Azure you may choose to get 200$ dollars on balance of the default subscription that you can spend on Azure services. It is a very useful option for beginners in cloud technologies to test different options.&lt;/p&gt;

&lt;p&gt;Now you are signed in, have a tenant and one subscription inside it. The next step is to decide which Azure services to use for your apps hosting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choose the appropriate Azure services&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Azure offers three main cloud computing platform services: SaaS (Software as a Service), IaaS (Infrastructure as a Service), PaaS (Platform as a Service). The main differences and maintaining levels are displayed on the diagram below: &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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuhcnvgel49ek6t0rrfhx.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuhcnvgel49ek6t0rrfhx.jpeg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you don’t want to be responsible for the operating system, data, runtime and middleware, but still need to manage and configure the application, the PaaS cloud computing service is a good choice. &lt;/p&gt;

&lt;p&gt;So, PaaS — it is where Azure provider hosts the hardware and software on its own infrastructure and delivers this platform to the user as an integrated solution, solution stack, or service through an internet connection, while the developer is allowed to develop, run, and manage his own apps without having to build and maintain the infrastructure or platform usually associated with the process. &lt;/p&gt;

&lt;p&gt;When we have decided which cloud computing service to use, let's proceed to the next step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating required resources&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The next step is to create the App Service Plan and the Resource Group.&lt;/p&gt;

&lt;p&gt;An &lt;strong&gt;&lt;em&gt;App Service Plan&lt;/em&gt;&lt;/strong&gt;, in two words, at a very high level is just the container in which your web applications run. It is used to determine the resources available to your application (or applications) and their boundary. Comparing this to an on premises environment, the app service environment is one server or servers on which your application is deployed. The app service plan defines what configuration of hardware your app runs on and how many servers you have. You can deploy multiple web applications inside the same App Service Plan. You do not need a separate web app plan for each web app.&lt;/p&gt;

&lt;p&gt;When you create an App Service plan in a certain region (for example, Western Europe), a set of compute resources is created for that plan in that region. Whatever apps you put into this App Service plan run on these compute resources as defined by your App Service plan.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;&lt;em&gt;resource group&lt;/em&gt;&lt;/strong&gt; is a logical container into which Azure resources like web apps, databases, and storage accounts are deployed and managed. The Resource Group can include all the resources for the solution, or only those resources that you want to manage as a group. You decide how to allocate resources to resource groups based on what makes the most sense for your organization. Generally, add resources that share the same lifecycle to the same resource group so you can easily deploy, update, and delete them as a group.&lt;/p&gt;

&lt;p&gt;Steps to create App Service Plan with Resource Group simultaneously:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Type App Service Plan in the search bar, select it from the dropdown and click &lt;em&gt;+Create new.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnxwoizxozmxxqhzstntf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnxwoizxozmxxqhzstntf.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Now you need to configure it. As you don’t have the Resource Group yet, press create new, enter its name, and it will be created with the App Service Plan and placed inside it. Some other tips: &lt;/li&gt;
&lt;li&gt;Enter the App Service Plan name that will clearly describe group of resources inside it (for example, name of the project or of the group of projects)
select the region (the better option is to choose the closest region to your customers' location because it will affect the latency)&lt;/li&gt;
&lt;li&gt;Select operating system to run your apps, in this case Linux was selected &lt;/li&gt;
&lt;li&gt;Select the pricing tier. You can choose from dev/test or production plans. But in case you want to configure automatic deployment from GitHub, choose the P1V2 or higher pricing tier. The application plans less than P1V2 have a list of limitations. The next features are not available:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;a) &lt;em&gt;Auto-scale feature&lt;/em&gt;. Autoscale is a built-in feature of Cloud Services, Mobile Services, Virtual Machine Scale Sets, and Websites that helps applications perform their best when demand changes.&lt;br&gt;
b)   &lt;em&gt;Daily backups.&lt;/em&gt; Here, probably, nothing to explain.&lt;br&gt;
c)   &lt;em&gt;Traffic manager&lt;/em&gt; improves performance and availability by routing traffic between multiple instances of your app.&lt;br&gt;
d)   &lt;em&gt;Staging slots&lt;/em&gt;. Useful for testing and deployments before swapping them into production.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you want to create a high volume of resources in the future, use tags. Azure tags are name-value pairs that are used to organize resources in Azure Portal. You can apply tags for individual resources or tag the resource group that they are part of.&lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5stgnl1wrkeey82rmaru.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5stgnl1wrkeey82rmaru.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Press Review and create. It can take up to 10 minutes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;App Service Plan and the Resource Group are ready to place resources inside. That’s why we can proceed to the next steps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating instances for applications&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As PaaS was selected, we should search among its services. The appropriate service is App Service. It enables you to build and host web apps, mobile back ends, and RESTful APIs in the programming language of your choice without managing infrastructure. It offers auto-scaling and high availability, supports both Windows and Linux, and enables automated deployments from GitHub, Azure DevOps, or any Git repo.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;To create the App Service find this category in the search bar and press +Create. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You will be redirected to this service configuration page. You need to select from the dropdown the subscription on the resource group, where it needs to be located. Put the name of the application (for example my-project-back-end-development).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the Publish tab select Code option if you are going to just put the code of your project instead of the ready Docker container. It will make Azure create the Docker container for you itself and run your application inside it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select Node from the dropdown of runtime stack. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The application region and operating system will be chosen automatically, according to your App Service Plan settings. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Press next and in the Monitoring section I fully recommend you to switch on Application Insights. It allows you to automatically monitor your application. It will automatically detect performance anomalies and includes powerful analytics tools to diagnose issues and to understand how users actually use your app. It's designed to help you continuously improve performance and usability. It works for apps on various platforms, including .NET, Node.js, Java, and Python hosted on-premises, hybrid, or any public cloud. It integrates with your DevOps process and has connection points to various development tools. All other settings, at this moment, let's keep by default. Click create and review, check if all settings are correct, and confirm. It can take up to 5-10 minutes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fca7ddcye3khplbificzr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fca7ddcye3khplbificzr.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The instance for hosting the back-end is ready, and you can reproduce previous steps to create a separate App Service instance for the front-end application. Once it is ready we go to the next part.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating instances for database&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As mentioned, MongoDB is used in the project. Azure has an opportunity to place MongoDB using the Azure Cosmos DB's API for MongoDB. It has some limitations. With the full list of supported operators and limitations or exceptions you can familiarize by the &lt;a href="https://docs.microsoft.com/en-us/azure/cosmos-db/mongodb/feature-support-40" rel="noopener noreferrer"&gt;link&lt;/a&gt;; To create DB go to Azure Cosmos DB Resource and click on Create Azure Cosmos DB account. On the next screen select Azure Cosmos DB API for MongoDB. &lt;/p&gt;

&lt;p&gt;The instance for hosting the database is ready, and you As on previous steps, select subscription and resource group, enter the database name. Select the location closest to the rest of your resources and customers to decrease the requests time. Select the Mongo version.&lt;/p&gt;

&lt;p&gt;Choosing the capacity mode of the instance is an important step to save your money. You need to know the differences between these two options. Provisioned has throughput at a constant rate, regardless of whether operations are being performed on our Cosmos DB account. Serverless Mode — we only use throughput when operations are performed on our Cosmos DB resources. Each of these options has pros and cons and if you want to know more, follow the &lt;a href="https://docs.microsoft.com/en-us/azure/cosmos-db/throughput-serverless" rel="noopener noreferrer"&gt;link&lt;/a&gt;. But in two words, serverless — pay only when using, provisioned — reserve capacity for the instance and pay for it all the time. I need to highlight that it is cheaper to use the serverless mode for non-highly loaded projects. Press the create button and wait until it is ready.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr9eomsscm3dyzhowqjt4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr9eomsscm3dyzhowqjt4.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s check what we have at the moment. You can find all the created instances in your resource group on Azure Portal. Each of the application instances are already available with the Microsoft example page by the url, which you can find in the app essentials section. Cosmos db account is ready for moving your database into it.&lt;/p&gt;

&lt;p&gt;Now all resources are ready to deploy your applications and database. The &lt;a href="https://dev.to/halolab/part-2-quick-guide-to-make-your-azure-applications-work-gd1"&gt;next part of the article&lt;/a&gt; is going to be about the migration processes and how to connect all instances. Make sure you read both parts of the article and then proceed to work because we will talk about database migration in the next steps.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>mongodb</category>
      <category>strapi</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Code Complete: Is It a Big White Elephant on Your Working Desk?</title>
      <dc:creator>Mitya Dementiy</dc:creator>
      <pubDate>Tue, 07 Dec 2021 09:59:18 +0000</pubDate>
      <link>https://dev.to/halolab/code-complete-is-it-a-big-white-elephant-on-your-working-desk-364h</link>
      <guid>https://dev.to/halolab/code-complete-is-it-a-big-white-elephant-on-your-working-desk-364h</guid>
      <description>&lt;p&gt;When I &lt;a href="https://twitter.com/De_Mityai/status/1403641281461506048" rel="noopener noreferrer"&gt;tweeted about my intention to read Code Complete&lt;/a&gt;, I got a couple of warning replies. I found out that the book is "a waste of time", "big white elephant on your desk" and "a dull book to while away the time in one's old age".&lt;/p&gt;

&lt;p&gt;But such feedback didn't disturb me because Code Complete is listed in books to read by Hexlet School of Witchcraft and Wizardry where I studied programming.&lt;/p&gt;

&lt;p&gt;The book was easy and fun to read. Yes, McConnel's humor is fire. So I laughed many times while reading a serious work about programming. But first thing's first.&lt;/p&gt;

&lt;h2&gt;
  
  
  The great and powerful Code Complete
&lt;/h2&gt;

&lt;p&gt;The book received Jolt Award in 1993, a prestigious award by Dr. Dobb's Journal for books on software development.&lt;/p&gt;

&lt;p&gt;It also received positive reviews from Martin Fowler, Grady Booch, and other famous software engineers and computer science experts.&lt;/p&gt;

&lt;p&gt;Hardback version of 900 pages weighs more than 1 kg. Probably, that is what frightens people away from this work. Let's open the book and find out if there is anything to be afraid of?&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbz8d3lwh4ikwyvlmuj0i.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbz8d3lwh4ikwyvlmuj0i.jpeg" alt="Code Complete McConnell"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Russian-language version of Code Copmplete by McConnell&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What McConnell wrote in 1993 and reasons to read it in the 21st century
&lt;/h2&gt;

&lt;p&gt;Code Complete is still relevant even though it was first published almost 30 years ago. This book contains very little information that could ever get out of date. McConell discusses fundamental coding principles that are unlikely to change within the next few years.&lt;/p&gt;

&lt;p&gt;The code examples are mainly in Visual Basic, Java and C++. But the book's main points make sense regardless of specific languages.&lt;/p&gt;

&lt;p&gt;There is a difference between programming into the language and in It.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Programming in your language limits your programming thinking only to the constructs that the language directly supports. If the language tools are primitive, the programmer's thought will also be primitive. Programmers who program "into" a language first decide what thoughts they want to express, and then they determine how to express those thoughts using the tools provided by their specific language. — Steve McConnel.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I had the feeling that there is not that much code in Code Complete.&lt;br&gt;
The author talks about coding in general and occasionally goes to specifics and illustrates his points with examples.&lt;/p&gt;

&lt;p&gt;He pays big attention to the process of development — from requirements gathering and choosing the technology to coding, testing,  debugging, refactoring, and optimization.&lt;/p&gt;

&lt;h3&gt;
  
  
  Metaphor is a programmer’s weapon
&lt;/h3&gt;

&lt;p&gt;The book starts with an explanation of why metaphors are important. One of the metaphors offered is building construction. &lt;/p&gt;

&lt;p&gt;Metaphors help both developers and any people they work with, such as managers, designers, and clients.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mistakes that cost the most
&lt;/h3&gt;

&lt;p&gt;They occur on the stage of requirements gathering and designing. &lt;/p&gt;

&lt;p&gt;It is easy to explain with building construction metaphors. If you make mistakes when laying the foundation, it will be difficult to fix them when the building is nine floors high.&lt;/p&gt;

&lt;h3&gt;
  
  
  "Dirty" problems
&lt;/h3&gt;

&lt;p&gt;These are the problems that can be defined only by partially or fully fixing them. I bet every programmer had a situation when a manager asked you to define the time needed for your task. And you explain that it is impossible because you actually have to solve the task first. This is what McConnel calls a dirty problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Managing complexity
&lt;/h3&gt;

&lt;p&gt;Managing complexity is the main technical aspect of software development. McConnel quotes Dijkstra, who pointed out that no one's skull is really big enough to contain a modern computer program. This means that software developers shouldn't try to cram whole programs into our skulls at once. We should try to organize our programs in such a way that we can safely focus on one part of it at a time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Software correctness and software robustness have an inverse relationship
&lt;/h3&gt;

&lt;p&gt;This was a huge insight for me. &lt;/p&gt;

&lt;p&gt;For some software robustness is more important than correctness, for some conversely.&lt;/p&gt;

&lt;p&gt;For instance, safety-critical software for a spaceship would require a high level of correctness. And we would have to sacrifice correctness in favour of robustness.&lt;/p&gt;

&lt;p&gt;Please, leave comments about your interpretation of this point and if you agree with it.&lt;/p&gt;

&lt;h3&gt;
  
  
  WISCA phenomenon
&lt;/h3&gt;

&lt;p&gt;Why Isn’t Sam Coding Anything? Non-tech people suppose that programmers must be coding nonstop. Clients and bosses get nervous while programmers are planning or working on requirements.&lt;/p&gt;

&lt;p&gt;McConnel gives us an easy way to fight WISCA phenomenon. Just keep a straight face and keep the source-code editor window open.&lt;/p&gt;

&lt;p&gt;By the way, on the sense of humor. McConnell inserts jokes on nearly every page. They are witty and specific. This is the famous programming humor in its purest form. &lt;/p&gt;

&lt;h2&gt;
  
  
  What I liked and disliked about the book
&lt;/h2&gt;

&lt;p&gt;I found the book helpful because it’s all about fundamentals. It helps to look for the forests before we look for the trees. And generalize problems and tasks.&lt;/p&gt;

&lt;p&gt;The book sure contains plenty of practical and specific examples or recommendations. The parts about variable naming, operators and mastery of programming are pure concentrated usefulness.&lt;/p&gt;

&lt;p&gt;I was happy that a big and serious book is written in easy language. Even examples in unfamiliar languages turned out to be comprehendible and useful.&lt;/p&gt;

&lt;p&gt;What I didn’t like is how quickly I finished the book. I also didn’t like the chapter on programming tools.The choice of compiler, IDE and other tools depends on which specific technology is used.&lt;/p&gt;

&lt;h2&gt;
  
  
  To read or not to read?
&lt;/h2&gt;

&lt;p&gt;Well, my conclusion is predictable. The book is worth the money and the time spent. It is more about basics in general rather than a handbook with practical guidelines. Thanks to Code Complete I gained a deeper understanding of coding in general. I started to see things that were out of my attention.&lt;/p&gt;

&lt;p&gt;Don’t be put off by the thickness of the book. I guarantee you’ll let out a chuckle many times when reading it.&lt;/p&gt;

</description>
      <category>books</category>
      <category>development</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to write a super simple reactive state manager</title>
      <dc:creator>Kapelianovych Yevhen</dc:creator>
      <pubDate>Wed, 03 Nov 2021 08:24:53 +0000</pubDate>
      <link>https://dev.to/halolab/how-to-write-a-super-simple-reactive-state-manager-12kh</link>
      <guid>https://dev.to/halolab/how-to-write-a-super-simple-reactive-state-manager-12kh</guid>
      <description>&lt;p&gt;Every application needs a state management system to have the ability to react to changes in the data. There are lots of state managers for every taste, from easy to understand ones to mind-breaking.&lt;/p&gt;

&lt;p&gt;Do you know how they work? What principles stand behind them? I'm sure you are. But these questions I asked myself not a long time ago, and in my opinion, it is still unknown territory for beginners. So, shall we go in?&lt;/p&gt;

&lt;p&gt;Behind most managers stands the &lt;code&gt;Observer&lt;/code&gt; pattern. It is a powerful pattern. It says that there is a &lt;code&gt;subject&lt;/code&gt; - a particular object encloses some data, and there are &lt;code&gt;observers&lt;/code&gt; - objects that want to know when that data changes and what value it has now. &lt;/p&gt;

&lt;p&gt;How will they know about the change? The &lt;code&gt;subject&lt;/code&gt; should tell them that he is changed. For that, every &lt;code&gt;observer&lt;/code&gt; should ask the &lt;code&gt;subject&lt;/code&gt; to notify it when something happens. It is a &lt;code&gt;subscription&lt;/code&gt;.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flifxdpt2uwowo7ofip8c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flifxdpt2uwowo7ofip8c.png" alt="Three observers subscribe to a target object"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And when some data changes, the subject notifies all known observers about that. That is a &lt;code&gt;notification&lt;/code&gt;.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5q8lo1yki2d894tv73ai.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5q8lo1yki2d894tv73ai.png" alt="The target object notifies observers about its update"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Pretty simple, yeah?&lt;/p&gt;

&lt;p&gt;Practically, there are many implementations for this pattern. We are going to show the simplest one.&lt;/p&gt;

&lt;p&gt;Basically, the data of your application aggregates into a restricted scope. In JavaScript, we can use an &lt;em&gt;object&lt;/em&gt; for that purpose. Each key represents a separated independent chunk of the data.&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;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;key1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;some useful data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;key2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;other useful data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// and so on&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can freely read and change these chunks as we want. But the problem is that we cannot predict when the change happens and what piece is changed with what value. Simply put, the &lt;em&gt;object&lt;/em&gt; &lt;em&gt;isn't reactive&lt;/em&gt;. Fortunately, JavaScript has a feature that helps us track any action that is made with any object. Its name is &lt;code&gt;Proxy&lt;/code&gt;. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Proxy&lt;/code&gt; is a wrapper around the object which can intercept and redefine fundamental operations for that object (&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy" rel="noopener noreferrer"&gt;MDN resource&lt;/a&gt;).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By default, &lt;code&gt;Proxy&lt;/code&gt; passes through all operations to the target object. To intercept them, you need to define &lt;em&gt;traps&lt;/em&gt;. A &lt;em&gt;trap&lt;/em&gt; is a function whose responsibility is to redefine some operation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;All operations and their trap names you can find [here].(&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/Proxy#handler_functions" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/Proxy#handler_functions&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With this ability, we can write our initial &lt;code&gt;store&lt;/code&gt; function. In the end, we should be able to do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;appState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;store&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Subscribe to the data changes.&lt;/span&gt;
&lt;span class="nx"&gt;appState&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;data&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;newValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// do something with a newValue&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Somewhere in the code&lt;/span&gt;
&lt;span class="nx"&gt;appState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;updated value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// observer is invoked&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As I said earlier, the &lt;code&gt;subject&lt;/code&gt; (our object with some data) should notify &lt;code&gt;observers&lt;/code&gt; (some entities) when its data was changed. That can be made only when the &lt;code&gt;subject&lt;/code&gt; knows what entities want to receive notifications. That means that the &lt;code&gt;subject&lt;/code&gt; should have a list of &lt;code&gt;observers&lt;/code&gt; inside.&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;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;observers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Proxy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="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;And now, we should define a &lt;em&gt;trap&lt;/em&gt; for assigning a new value to the target object. That behaviour defines a &lt;code&gt;set&lt;/code&gt; interceptor.&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;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;observers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Proxy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;observers&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After updating the value, the &lt;code&gt;subject&lt;/code&gt; notifies all &lt;code&gt;observers&lt;/code&gt; that were added to the list of observers. Great! We've created a notification behaviour. But how does the &lt;code&gt;subject&lt;/code&gt; add an &lt;code&gt;observer&lt;/code&gt; to the subscription list?&lt;/p&gt;

&lt;p&gt;The answer is that the &lt;code&gt;subject&lt;/code&gt; should expose a way to trigger this subscription. With &lt;code&gt;Proxy&lt;/code&gt; in mind, we can define a &lt;em&gt;virtual method&lt;/em&gt; that will accomplish that process. How can we do that?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Virtual method&lt;/em&gt; is a method that doesn't exist in the target object, but &lt;code&gt;Proxy&lt;/code&gt; emulates it by creating it outside of the target object.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As we know, a method is a property which value is a function. That tells us that we should define a &lt;code&gt;get&lt;/code&gt; interceptor and provide a handler for an absent property. At the same time, we shouldn't block access to the target's properties.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;observers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Proxy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;property&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;property&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;subscribe&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;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;observer&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;observers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;observer&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;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;observers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;observers&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may notice that the execution of the &lt;code&gt;subscribe&lt;/code&gt; function returns another function. Yes, indeed. Observers should be able to stop listening to changes when they want to. That's why &lt;code&gt;subscribe&lt;/code&gt; returns a function that will delete the listener.&lt;/p&gt;

&lt;p&gt;And that's it! We may want to make deleting a property reactive. As we did earlier, a &lt;code&gt;delete&lt;/code&gt; interceptor is for that.&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;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;observers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Proxy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;property&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;property&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;subscribe&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;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;observer&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;observers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;observer&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;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;observers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;observers&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;deleteProperty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;property&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;delete&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="nx"&gt;observers&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now our &lt;code&gt;store&lt;/code&gt; function is complete. There are a lot of places for improvements and enhancements. And it is up to you! 🤗&lt;/p&gt;

&lt;p&gt;Also, you can see a slightly better implementation in our &lt;a href="https://github.com/Halo-Lab/store" rel="noopener noreferrer"&gt;@halo/store&lt;/a&gt; package. A code from these examples lives in the &lt;code&gt;store.js&lt;/code&gt; file. But there is one more entity that is worth explaining. That's why we plan to write the next article precisely about it where we are going to explain the purpose of the package and in what situations you may need it. Hold tight and cheer up!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Supported by &lt;a href="https://www.halo-lab.com/" rel="noopener noreferrer"&gt;Halo Lab&lt;/a&gt; design-driven development agency&lt;/em&gt;&lt;/p&gt;

</description>
      <category>reactivity</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>proxy</category>
    </item>
    <item>
      <title>Kickin - bootstrap your Eleventy project</title>
      <dc:creator>Kapelianovych Yevhen</dc:creator>
      <pubDate>Mon, 18 Oct 2021 16:55:52 +0000</pubDate>
      <link>https://dev.to/halolab/kickin-bootstrap-your-eleventy-project-c11</link>
      <guid>https://dev.to/halolab/kickin-bootstrap-your-eleventy-project-c11</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Make your web pages fast on all devices - &lt;em&gt;Developers all over the world.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We always chase productivity on our pages. And Web development community has got many instruments that help achieve this goal. &lt;a href="https://www.11ty.dev" rel="noopener noreferrer"&gt;Eleventy&lt;/a&gt; is one of them. It is a great tool that offers an easy way of combining templates and data into fully operative static pages that you can host on a server.&lt;/p&gt;

&lt;p&gt;Unfortunately, it can bundle only templates and doesn't care about assets on the site, such as images, styles and scripts etc. So we decided to create a bundler based on Eleventy CLI 🤖&lt;br&gt;
It isn't separate, but we use &lt;a href="https://www.11ty.dev/docs/events/" rel="noopener noreferrer"&gt;Eleventy's events&lt;/a&gt; for integration.&lt;/p&gt;

&lt;p&gt;The primary tool is &lt;a href="https://www.npmjs.com/package/kickin" rel="noopener noreferrer"&gt;Kickin CLI&lt;/a&gt;. It quickly bootstraps a template folder with &lt;code&gt;Eleventy&lt;/code&gt; and necessary plugins for comfortable development. Some of them were built by ourselves:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;eleventy-plugin-compress&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;eleventy-plugin-pwa-icons&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;eleventy-plugin-scripts&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;eleventy-plugin-styles&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;eleventy-plugin-workbox&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;eleventy-shortcode-image&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We don't recommend installing CLI globally. Instead, use a &lt;a href="https://docs.npmjs.com/cli/v7/commands/npx/" rel="noopener noreferrer"&gt;npx&lt;/a&gt; for project initialization.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The minimal required version of NodeJS is &lt;strong&gt;12.17.0&lt;/strong&gt;. The reason is that Kickin CLI consists of ES modules.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It exposes command that is named after itself - &lt;code&gt;kickin&lt;/code&gt;. And its use is pretty simple.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx kickin name-of-your-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you already have such a folder, you can use the &lt;code&gt;.&lt;/code&gt; symbol instead of the name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd my-project-name
npx kickin .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait until the installation of dependencies completes, and that's all 🤗 &lt;/p&gt;

&lt;h3&gt;
  
  
  After
&lt;/h3&gt;

&lt;p&gt;There are four main commands available in the created project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;npm start&lt;/code&gt; - starts development server on &lt;code&gt;http://localhost:3000&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;npm run build&lt;/code&gt; - builds project.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;npm run serve&lt;/code&gt; - runs a local server with secure protocol on &lt;code&gt;https://localhost:3000&lt;/code&gt;. It helps to mimic the production environment.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;npm run certs&lt;/code&gt; - creates certificates for the ability to run site with HTTPS locally.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;We use &lt;a href="https://github.com/FiloSottile/mkcert" rel="noopener noreferrer"&gt;mkcert&lt;/a&gt; to generate SSL certificates. Make sure you installed it on your local machine as well.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can change any part of the generated project as you want - configuration file and all dependencies are open to being changed.&lt;/p&gt;

&lt;p&gt;Let's explore a little bit of what and where CLI installs.&lt;/p&gt;

&lt;h4&gt;
  
  
  Structure
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Source code is located in the &lt;code&gt;src&lt;/code&gt; folder.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;assets&lt;/code&gt;: this folder supposed to be home for static content: images, fonts, video, audio etc.

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;images&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fonts&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;video&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;audio&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;components&lt;/code&gt; - folder where &lt;a href="https://www.11ty.dev/docs/config/#directory-for-includes" rel="noopener noreferrer"&gt;Eleventy's components&lt;/a&gt; are located (default name is &lt;code&gt;_includes&lt;/code&gt;)&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;layouts&lt;/code&gt; - folder for &lt;a href="https://www.11ty.dev/docs/layouts/#layouts" rel="noopener noreferrer"&gt;layouts&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;pages&lt;/code&gt; - place where future site's pages live.&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;scripts&lt;/code&gt; - folder for scripts that will be used in HTML.&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;styles&lt;/code&gt; - folder for styles.&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;&lt;p&gt;For bundled code, the &lt;code&gt;build&lt;/code&gt; folder is preserved.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Inner structure of defined directories is up to you 🙃&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's dig into plugins a little bit. There are 6 of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.npmjs.com/package/eleventy-plugin-compress" rel="noopener noreferrer"&gt;eleventy-plugin-compress&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;This plugin is used to compress &lt;code&gt;HTML&lt;/code&gt;, &lt;code&gt;CSS&lt;/code&gt; and &lt;code&gt;JS&lt;/code&gt; using &lt;code&gt;brotli&lt;/code&gt;(&lt;em&gt;default&lt;/em&gt;), &lt;code&gt;gzip&lt;/code&gt; or &lt;code&gt;deflate&lt;/code&gt; algorithms. It helps you reduce the size of files that are sent over the internet.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://wp-rocket.me/blog/brotli-vs-gzip-compression/" rel="noopener noreferrer"&gt;Why brotli?&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.npmjs.com/package/eleventy-plugin-pwa-icons" rel="noopener noreferrer"&gt;eleventy-plugin-pwa-icons&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;If you want to create PWA,  you will need icons for your application for different platforms. This package uses &lt;a href="https://github.com/onderceylan/pwa-asset-generator" rel="noopener noreferrer"&gt;pwa-assets-generator&lt;/a&gt; to create icons from an image. It will automatically insert links to icons into the HTML of every page and in the &lt;code&gt;manifest.json&lt;/code&gt; file along with generated icons.&lt;br&gt;
All you need is an image as a template for future icons. By default, it is a &lt;code&gt;favicon.png&lt;/code&gt; under the &lt;code&gt;src&lt;/code&gt; directory.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;a href="https://www.npmjs.com/package/eleventy-plugin-scripts" rel="noopener noreferrer"&gt;eleventy-plugin-scripts&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Starter supports modern JavaScript syntax (except for Eleventy's templates) and &lt;a href="https://www.typescriptlang.org" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;All scripts files should be in the &lt;code&gt;scripts/&lt;/code&gt; directory, but the inner structure does not matter.&lt;/p&gt;

&lt;p&gt;To include scripts into an HTML page, provide &lt;code&gt;scripts&lt;/code&gt; property in page template's front matter zone (can be either type of &lt;em&gt;string&lt;/em&gt; or &lt;em&gt;array of strings&lt;/em&gt;). The path to the script is relative to &lt;code&gt;src/scripts&lt;/code&gt; directory, so you do not need to include this prefix in the URI.&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;// For JavaScript templates&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// This will be resolved to 'src/scripts/main.js'&lt;/span&gt;
  &lt;span class="na"&gt;scripts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;main.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;// or 'main.ts' -&amp;gt; 'src/scripts/main.ts'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;a href="https://www.npmjs.com/package/eleventy-plugin-styles" rel="noopener noreferrer"&gt;eleventy-plugin-styles&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The configuration of this one is very similar to &lt;code&gt;eleventy-plugin-scripts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In &lt;em&gt;Kickin&lt;/em&gt; &lt;a href="https://sass-lang.com" rel="noopener noreferrer"&gt;Sass language&lt;/a&gt; is supported.&lt;/p&gt;

&lt;p&gt;Stylesheets should be in &lt;code&gt;styles/&lt;/code&gt; directory, but the inner structure does not matter. They will be compiled, minified and cleaned from unused selectors automatically.&lt;/p&gt;

&lt;p&gt;To include style to page in the template, provide &lt;code&gt;styles&lt;/code&gt; property in front matter zone. It can be &lt;em&gt;string&lt;/em&gt; or &lt;em&gt;array of strings&lt;/em&gt;. The path to the stylesheet is relative to &lt;code&gt;src/styles&lt;/code&gt; directory, so you do not need to include this prefix in the URI.&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;// For JavaScript templates&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Bundler of this starter is smart enough to recognize type of style&lt;/span&gt;
  &lt;span class="c1"&gt;// and its location (file will be resolved to `src/styles/home.scss`)&lt;/span&gt;
  &lt;span class="na"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;home.scss&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;If you want to put your CSS file in the inner folder, say &lt;code&gt;directory/common.scss&lt;/code&gt; , don't forget to mention it in your config:&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;// For JavaScript templates&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;directory/common.scss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// -&amp;gt; src/styles/directory/common.scss&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is the most potent package of all! Whew... Amazing!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.npmjs.com/package/eleventy-plugin-workbox" rel="noopener noreferrer"&gt;eleventy-plugin-workbox&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Adds the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers" rel="noopener noreferrer"&gt;Service worker&lt;/a&gt; that will automatically cache all assets of your site on a client.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Registration of service worker script will be automatically injected into each HTML page.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By default, the worker will cache static resources (images, fonts, audio files etc.) and try to use them from the cache at first. Dynamic resources that can be changed often (HTML, JS, CSS) are cached also, but on every request, it will try to fetch it on the server at first.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can read more about strategies &lt;a href="https://developers.google.com/web/tools/workbox/reference-docs/latest/module-workbox-strategies" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.npmjs.com/package/eleventy-shortcode-image" rel="noopener noreferrer"&gt;eleventy-shortcode-image&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;It handles images of your page. It can properly rebase, minify and generate optimal types of images that all browsers support. It uses &lt;a href="https://www.11ty.dev/docs/plugins/image/" rel="noopener noreferrer"&gt;@11ty/eleventy-img&lt;/a&gt; under the hood but also can minify SVGs (uses &lt;a href="https://github.com/svg/svgo" rel="noopener noreferrer"&gt;SVGO&lt;/a&gt;). Compression is disabled in development mode to reduce build time. You want a quick response on your changes, aren't you? 😊 So, we do too.&lt;/p&gt;

&lt;p&gt;For this purpose, the CLI includes an &lt;code&gt;image&lt;/code&gt; shortcode. Use it to incorporate images to HTML (either raster or vector(SVG) ones).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Info about shortcodes and how to use them is &lt;a href="https://www.11ty.dev/docs/shortcodes/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Signature of shortcode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ImageAttributes&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/** Defines alternative text for image. */&lt;/span&gt;
  &lt;span class="nl"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="cm"&gt;/** Defines title for image. */&lt;/span&gt;
  &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="cm"&gt;/** Class name(s) for `class` attribute. */&lt;/span&gt;
  &lt;span class="nl"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;ReadonlyArray&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ImageAttributes&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first parameter is mandatory and contains an image path relative to the &lt;code&gt;src/assets/images&lt;/code&gt; directory.&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;// For JavaScript templates&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&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="k"&gt;return&lt;/span&gt; &lt;span class="cm"&gt;/* html */&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;main&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;logo.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/main&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;For example, &lt;em&gt;logo.png&lt;/em&gt; image will be resolved to &lt;code&gt;src/assets/images/logo.png&lt;/code&gt;, then &lt;code&gt;webp&lt;/code&gt; and &lt;code&gt;avif&lt;/code&gt; images will be generated and placed along with the source image in the &lt;code&gt;build&lt;/code&gt; directory. In HTML, you will receive efficient images with the correct paths 😊!&lt;/p&gt;

&lt;p&gt;The same rules apply if you define a path to the image from CSS (for example, in the &lt;code&gt;URL&lt;/code&gt; function). But if you specify URL as absolute (&lt;strong&gt;absolute public URL&lt;/strong&gt;), it will be returned as-is without any changes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is done intentionally in case if you want to copy assets to the output directory.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;All these packages are attached to &lt;a href="https://www.11ty.dev/docs/config/#transforms" rel="noopener noreferrer"&gt;transform flow&lt;/a&gt; of Eleventy.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqks895vsmxi912nligqn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqks895vsmxi912nligqn.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It looks just like above. Every plugin transforms the HTML in its way and could produce new assets. Assets flow separated from Eleventy, but they are synchronised.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Configuration
&lt;/h3&gt;

&lt;p&gt;The default configuration of Eleventy is enough for most use cases, but sometimes there you need to change some behaviour.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.11ty.dev/docs/config/" rel="noopener noreferrer"&gt;&lt;code&gt;.eleventy.js&lt;/code&gt;&lt;/a&gt; is a starting point for Eleventy.&lt;/p&gt;

&lt;p&gt;If you want to change some behaviour or add new feature to site, place it in &lt;code&gt;.eleventy/&lt;/code&gt; directory. It has following structure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;filters&lt;/code&gt; - used for holding custom &lt;a href="https://www.11ty.dev/docs/filters/" rel="noopener noreferrer"&gt;filters&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;plugins&lt;/code&gt; - contains custom &lt;a href="https://www.11ty.dev/docs/plugins/" rel="noopener noreferrer"&gt;plugins&lt;/a&gt; for Eleventy.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;shortcodes&lt;/code&gt; - contains &lt;a href="https://www.11ty.dev/docs/shortcodes/" rel="noopener noreferrer"&gt;shortcodes&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;transforms&lt;/code&gt; - holds HTML transformer functions that changes generated HMTL by Eleventy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feel free to try it and give us feedback. We fell in love with these tools, and we hope you will too 🖤&lt;/p&gt;

&lt;h3&gt;
  
  
  Useful links:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/Halo-Lab/eleventy-packages" rel="noopener noreferrer"&gt;This is a repository where a code of all plugins live.&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Have fun! ✌️&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Supported by &lt;a href="https://www.halo-lab.com" rel="noopener noreferrer"&gt;Halo Lab&lt;/a&gt; design-driven development agency&lt;/em&gt;&lt;/p&gt;

</description>
      <category>eleventy</category>
      <category>cli</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Implementing the translate function with TypeScript</title>
      <dc:creator>Kapelianovych Yevhen</dc:creator>
      <pubDate>Sun, 03 Oct 2021 15:09:31 +0000</pubDate>
      <link>https://dev.to/halolab/implementing-the-translate-function-with-typescript-5d8d</link>
      <guid>https://dev.to/halolab/implementing-the-translate-function-with-typescript-5d8d</guid>
      <description>&lt;p&gt;TypeScript 4.1 has brought a nice feature called &lt;a href="https://devblogs.microsoft.com/typescript/announcing-typescript-4-1/#template-literal-types"&gt;Template literal types&lt;/a&gt;. Many authors have written about it, so I won't stop here and explain how it works. Instead, I would like to show you an example of how we can use it. Let's not waste our time!&lt;/p&gt;

&lt;p&gt;Every &lt;code&gt;i18n&lt;/code&gt; module has a &lt;code&gt;translate&lt;/code&gt; function (also can be named as short &lt;code&gt;t&lt;/code&gt;). Assume that we have a function with such a signature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As the first parameter, we can pass a dot delimited keys of a translation object. It can be a JSON object or JavaScript object, whatever. The main thing is that TypeScript can't check path correctness and possible variable existence in the translated sentence with such signature. Besides, you must be careful with what you are writing. Thanks to the new feature we can fix it.&lt;/p&gt;

&lt;p&gt;At first, we need to have a type that describes our translation object. It is up to you because no one knows how big and diversified it can be. Suppose we have it already. And our &lt;code&gt;translation&lt;/code&gt; function should know it. Otherwise, TypeScript can't make any prediction on unknown object shapes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;translate&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But it isn't helpful yet. Let's move on. Our goal is to let TypeScript check if keys of the &lt;em&gt;path&lt;/em&gt; parameter exist in the translation object and infer the following keys based on typed information.&lt;/p&gt;

&lt;p&gt;We can accomplish it by creating all possible ways to structure a path to all values in the object. It may be more clear if I show it with an example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="nl"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nl"&gt;d&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have an interface &lt;code&gt;T&lt;/code&gt;. For an object with such shape, we can build three possible &lt;em&gt;path&lt;/em&gt; parameters:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;a.b&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a.c&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;d&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And when you write &lt;code&gt;a&lt;/code&gt;, TypeScript will add a hint that the following path part can be either &lt;code&gt;.b&lt;/code&gt; or &lt;code&gt;.c&lt;/code&gt;. Do you get the idea?&lt;/p&gt;

&lt;p&gt;But how we can get all possible key combinations? We can recursively iterate over an object type and, for all top keys, get an array of all keys of inner objects that we can reach. It looks like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PathKeys&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="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;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;PathKeys&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&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="p"&gt;}[&lt;/span&gt;&lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stop a little bit and try to understand the type. It is a little bit tricky but works as expected. Can you see why?&lt;/p&gt;

&lt;p&gt;Ok, we have tuples of all possible key combinations. But it isn't what we want. So we should join them to have a union type of all combinations. For that, we should learn a new type that will concatenate the values of each tuple. Let's call it &lt;code&gt;Join&lt;/code&gt; 😎&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Join&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;Delimiter&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
 &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
 &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;F&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;F&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
 &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;Other&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt;
 &lt;span class="nx"&gt;F&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt;
 &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;F&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;Delimiter&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;Join&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Extract&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Other&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Delimiter&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is a bit trickier than the previous type, and we finally start using the new TypeScript feature. It accepts an array of strings (keys) and &lt;em&gt;delimiter&lt;/em&gt; value that is the &lt;em&gt;dot&lt;/em&gt; in our case. Then recursively iterates over the array(tuple). Unfortunately, TypeScript can't understand that the &lt;code&gt;Other&lt;/code&gt; type is another tuple with all values except the &lt;code&gt;F&lt;/code&gt; and infers it as &lt;code&gt;unknown[]&lt;/code&gt;, but we can fix it by providing a hack with an &lt;code&gt;Extract&lt;/code&gt; type that narrow &lt;code&gt;Other&lt;/code&gt; to a tuple of strings.&lt;/p&gt;

&lt;p&gt;And that's it! Now we should make &lt;em&gt;path&lt;/em&gt; parameter as union type of all keys combinations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;translate&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Join&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PathKeys&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yay!&lt;/p&gt;

&lt;p&gt;But one thing left. Our text can have variables, and we can provide values for them. Are we able to let TypeScript check for variable presence in translation sentences and check for name correctness? Yes, we are.&lt;/p&gt;

&lt;p&gt;To do that, we should analyze a string and check whether it has a particular template for a variable. Suppose it is &lt;code&gt;{variableName}&lt;/code&gt;. As the previous types, the new type will also be recursive.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;SearchForVariable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;{&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;B&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;}&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
 &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;SearchForVariable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;B&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;SearchForVariable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&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;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We split a string into three parts: before a template, template itself and after the template. Returned union type will contain all variable names that exist in the string value or nothing.&lt;/p&gt;

&lt;p&gt;But how we actually can get the correct value for checking? For that, we should match the initial translation object and path to the &lt;code&gt;string&lt;/code&gt; value. Do you know what it means? Yes, a new type! Let's dig into it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Variables&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Path&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Delimiter&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
 &lt;span class="nx"&gt;Path&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;Delimiter&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;O&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
 &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;
 &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;Variables&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Extract&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;object&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;O&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Delimiter&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;never&lt;/span&gt;
 &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Path&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
 &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;
 &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;SearchForVariable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Extract&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
 &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;
 &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is the trickiest type of this tutorial. At first, we should get rid of the &lt;em&gt;delimiter&lt;/em&gt;. Then every part of the inferred values is recursively checked. If at least one part contains a variable template, then it is returned. If there are two variables or more, then the union type of their names is the result. So, the final type of &lt;code&gt;translate&lt;/code&gt; function looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;translate&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Join&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PathKeys&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Variables&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&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="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have built a complete &lt;code&gt;translate&lt;/code&gt; function that TypeScript can check for correctness. You must have a concrete translation type object with values as literal string types for it to work. Otherwise, TypeScript won't make any checks 🤷‍♂️.&lt;/p&gt;

&lt;p&gt;As a bonus, you can allow spaces between &lt;code&gt;{}&lt;/code&gt; and variable names. But in that case, you should trim extra whitespaces from the name. A new type called &lt;code&gt;Trim&lt;/code&gt; can help you with that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Trim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="s2"&gt;` &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;B&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;Trim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;B&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;A&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; `&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;Trim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&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;A&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, you should correct the &lt;code&gt;SearchForVariable&lt;/code&gt; type to perform the trim operation over the variable's name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;SearchForVariable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;{&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;B&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;}&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
 &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;SearchForVariable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Trim&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;B&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;SearchForVariable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;C&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;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A small update. And now we are finally done. &lt;a href="https://www.typescriptlang.org/play?#code/C4TwDgpgBACghsAFgaQiAzgHgCoD4oC8U2UEAHsBAHYAm6U6wATgJZUDmUA-FANoC6UAFxQA3gCgoUvsihsoAazQB7AGbF+I3sgA0UAHSH4SVBhzb+ufuIC+vJSDUaA3OPGhIUAFLK2OUhTUdAzMbOwCegAiEAA2LAC2LJRMAZS09IysHPgEktIk5GnBAtxQVBAAbhApQnlSBYHpfGyq1VAAYoI87cJ1xKlB9Lwtbe16hvojKQDySNVdfT2FgyFZnFx9AAYAJKLtNrvRcYnJB6I+fgCiFExwAMbAmLOI1XqZYQK4UbEJSdW4Nk2wjKlTaIneHFcbg80GwrHimAAggMmhD2DkoMjlk0gbsplAAEKA0pwhKYAn4ERYxrBHaifEAYRsUCBPFJCIZlMxUJhUAAyhA4Ew7oh2somAA1IUsOAAIxiECRKOCaIx1KK9Dp+MRNlEeKorRSRLOjMBfR4AqFIrFkulcoVSPwAB9iPDyc7+YLhaLxVLWPbFZy+iJylUmDzwNA-TL5RAsA0NaswlAXcpZQArCAPPTGRDKjKhDjfY5-FLYlWF9GEPq5-Ms-WGzFnI6-U4NtrTM3SUrqlYOJzYc1QaMBrDXZj3R7YXiI-hvSspqBpzMPL5QabF1v-YMgsM72vlzXtlI6zZD3tNfvqQfdi1e62+u2xzDj24Pcyz+drXC4Heh6p-qC4ZuDQWYxEK0CqAArlQDwsMoVBQBOVDoOBlCYDAdYXFQGEICgaDxmuADk+hET+AAUYB4egIgwHoFRCugXAiAASlm4o0JgI6xvGOZ6CRZFfmEuAAJTgpWUJsMkqj3LCYh9HAIgSN23aykpfQqdIdwiERiDKERGnSDYOiGVIspCjpohQPEgpUMmmlGd2ojKHMTDMgZ3bGX0qjKMoOnmQAXmIyhQcA6AsKBNgGTYbjiHcCGMFAcCEEhtwoWhEDkURcD6OZTBEXoVk2XAdkcDpekFUurk6fpUA2CJ4hAA"&gt;The final implementation you can see here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you for reading. TypeScript is a great language and gets more power with each release. I hope you had fun and learned something new. May the wisdom be with you.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Supported by &lt;a href="https://www.halo-lab.com"&gt;Halo Lab&lt;/a&gt; design-driven development agency&lt;/em&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>tutorial</category>
      <category>i18n</category>
    </item>
  </channel>
</rss>
