<?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: Pegah Safaie</title>
    <description>The latest articles on DEV Community by Pegah Safaie (@pegahsafaie).</description>
    <link>https://dev.to/pegahsafaie</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F579581%2F6aa0adeb-8c03-46e4-8123-14f4930dd3a7.jpg</url>
      <title>DEV Community: Pegah Safaie</title>
      <link>https://dev.to/pegahsafaie</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pegahsafaie"/>
    <language>en</language>
    <item>
      <title>Keep An Eye On These Build Tools For Your Web Apps</title>
      <dc:creator>Pegah Safaie</dc:creator>
      <pubDate>Sun, 23 May 2021 07:10:59 +0000</pubDate>
      <link>https://dev.to/pegahsafaie/keep-eyes-on-these-build-tools-for-your-webapps-3abj</link>
      <guid>https://dev.to/pegahsafaie/keep-eyes-on-these-build-tools-for-your-webapps-3abj</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;You might remember the battle in which webpack won over module loaders and task runners such as requireJS and gulp.&lt;br&gt;
For a while, most of the webapps were built and bundled with webpack. Libraries on the other hand mostly preferred rollup as bundler.&lt;br&gt;
But things are changing. There is a new generation of fast build tools that has a pretty good chance to keep up or even overtake Webpack. They might not be yet mature enough for production, but they are on the right path, so they are worth monitoring.&lt;/p&gt;
&lt;h2&gt;
  
  
  What are these fast build tools?
&lt;/h2&gt;

&lt;p&gt;Vite,  Snowpack and esbuild. &lt;/p&gt;
&lt;h2&gt;
  
  
  What makes them alternative for webpack?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;They are fast&lt;/li&gt;
&lt;li&gt;In what?&lt;/li&gt;
&lt;li&gt;Build time &lt;/li&gt;
&lt;li&gt;How?&lt;/li&gt;
&lt;li&gt;The bundling is excluded from the build process of "Vite" and "Snowpack" and "esbuild" is being written in Go instead of javascript!&lt;/li&gt;
&lt;li&gt;now I know the names. Why should I read on?&lt;/li&gt;
&lt;li&gt;Because I want you to deeply understand how and why we need bundling and how and why we can exclude it from your build process! So stay with me if you are interested.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  This would be a history lesson. But why?
&lt;/h2&gt;

&lt;p&gt;When talking about a tool/concept in our ecosystem, it is important to keep in mind that these tools/concepts are created in response to the needs of their times. Therefore, to understand how a tool is built, we need to put it in the context of time and understand what problem it was supposed to solve at the time. By using this approach, you won't continue to believe in something just because your fathers did ;)&lt;br&gt;
Here is the history of evolving JS module systems and their impact on task runners, module loaders, build tools and bundlers.&lt;/p&gt;
&lt;h3&gt;
  
  
  Problems of a world without having modules
&lt;/h3&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%2Fyifyupckzjjt5uy0dxfv.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%2Fyifyupckzjjt5uy0dxfv.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
The first javascript project I saw had a huge main.js file referenced by a script tag in index.html. Later some colleagues complained about the mess in this huge file, so we decided to write every single feature in one file and include all of them as script tags in index.html file.&lt;/p&gt;

&lt;p&gt;We detected a problem very quickly: We were all working on different files and each had his own variables. In some cases, we could have used the same variable names in separate files.&lt;br&gt;
Why was there a problem?&lt;/p&gt;

&lt;p&gt;The variables inside a function in JavaScript are limited to that function, but everything outside of the function is global and accessible even from other scripts referenced in the same HTML page (that changed after introducing ES2015 and defining module and block scope besides  function scope). Suppose everyone were to change the variable you depend on, you could easily run into conflict.&lt;/p&gt;
&lt;h3&gt;
  
  
  IFFE pattern, one step forward
&lt;/h3&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%2Fdw9mo6pswyytix9bhwdb.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%2Fdw9mo6pswyytix9bhwdb.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
The IIFE pattern was introduced to solve the &lt;strong&gt;name collision(encapsulation)&lt;/strong&gt; problem we saw in the previous section.&lt;br&gt;
By looking at the picture, we see that the authors of external.js and func1.js wrapped their code into an immediately executing function&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;(()&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;This function returns the functions and variables we want to export. &lt;br&gt;
When our name collisions problem was resolved, we had some free time to start complaining about another issue in the non-module world: &lt;strong&gt;dependency management&lt;/strong&gt;. Let me put it into the context:&lt;br&gt;
-Dependency: An external code your code depends on. For example, func1.js is a dependency of main.js and external.js is a dependency of func1.js&lt;br&gt;
-Management: Refrencing JS libraries (scripts) in an HTML file with a script tag.&lt;/p&gt;

&lt;p&gt;Managing dependencies using script tags was a challenging task for three reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The order in which scripts are included matters. The code above does not work if main.js is referenced after func1.js.&lt;/li&gt;
&lt;li&gt;If your external library requires other dependencies, you must be aware of and specify all of their dependencies.&lt;/li&gt;
&lt;li&gt;For the newer version, you must check the creator's website regularly and replace the old address in the index.html with the new one.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  CJS modules, node and NPM. A revolution in dependency management
&lt;/h3&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%2F4fte0bs8r9e7a36id0a3.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%2F4fte0bs8r9e7a36id0a3.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Nodejs was born in 2009 and revolutionized the modules world. As Nodejs applications don't have any html files in which dependencies can be defined, the Nodejs society has developed its own way of writing modular code, which turned out to be better than the IFFE pattern. The system was called CommonJS module system (CJS).&lt;/p&gt;

&lt;p&gt;IFFE and CJS both support encapsulation, but CJS(+npm) has a more efficient way of handling dependencies. As an example, imagine you need to use lodash in one of your modules. Instead of placing &lt;code&gt;&amp;lt;script src='./lib/lodash'&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt; inside of index.html which makes it available and global for all your modules, you can place&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;lodash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./lib/lodash&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;inside the js file you want to use lodash.&lt;/p&gt;

&lt;p&gt;If you have already used the &lt;code&gt;require&lt;/code&gt; syntax to import modules you might get confused by the relative address whitin &lt;code&gt;require&lt;/code&gt;. what we write nowadays looks like:&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;lodash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lodash&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference lies in NPM(Node Package Manager) and your &lt;code&gt;package.json&lt;/code&gt; file.&lt;br&gt;
You can use the latter code by adding the lodash to your package.json file and then running the &lt;code&gt;npm install&lt;/code&gt; command. NPM downloads the latest version of lodash(based on the semver rules you specifies for lodash) and put it in the &lt;code&gt;node_modules&lt;/code&gt; folder. By writing &lt;code&gt;require('lodash')&lt;/code&gt;, Node finds and reads the content of the "lodash" folder within node_modules.&lt;br&gt;
CJS was(and continues to be) widely accepted in javascript ecosystem and many famous libraries like lodash are written using this system.&lt;/p&gt;

&lt;p&gt;Nodejs also led to the emergence of Modejs task runners(2011) like Grunt and Gulp that were used alone or in conjunction with other build tools to manage our development pipelines and accomplish tasks like minifying and concatenation(both helped to reduce the amount of code you deploy and the others have to download). The field of build tools was dominated by them until 2015, when webpack arrived.&lt;/p&gt;

&lt;p&gt;The problem with CJS is that it cannot be used in a browser! When you run &lt;code&gt;npm install&lt;/code&gt;, NPM will still download lodash and place it under the lodash folder in node_modules.  However, unlike node, browser does not know what to do with  &lt;code&gt;require('lodash')&lt;/code&gt;. &lt;/p&gt;
&lt;h3&gt;
  
  
  AMD modules and module loaders
&lt;/h3&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%2Fgcg3hsfp2954grtgjd4q.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%2Fgcg3hsfp2954grtgjd4q.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There were two main reasons why CJS was not suitable for browsers: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In CJS, only one module per file is allowed  This increases the network traffic.&lt;/li&gt;
&lt;li&gt;Dependencies(modules) can not be loaded asynchronously. &lt;code&gt;require&lt;/code&gt; is a sync command. When you have ten require dependencies, they all will be loaded one after the other. Nodejs dos'nt have any issues with that since everything executing on the server and IO actions are executed really quickly. However, the browser will freeze until all 10 are downloaded. By comparison, an async module load sends ten requests at the same time (even when they are dependent on one another) and serves the user even while the dependencies are downloading.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To resolve these two issues, frontend developers devised &lt;a href="https://requirejs.org/docs/whyamd.html#amd" rel="noopener noreferrer"&gt;AMD module&lt;/a&gt; which come with RequireJS as its module loader.&lt;br&gt;
But what is a module loader for?&lt;/p&gt;

&lt;p&gt;Do you remember how Node supported CJS to manage dependencies?&lt;br&gt;
Well, no browser do it for AMD. That's why AMD needs its own dependency manager which loads as a script in the browser and performs the exact same functions as node did for CJS.&lt;br&gt;
&lt;strong&gt;AMD Module loaders manage dependencies for AMD module systems in an async manner!&lt;/strong&gt; Lets see an example to understand it better.&lt;/p&gt;

&lt;p&gt;Main.js depends on two dependencies, A and B. RequireJS loads B and then A asynchronously(at the sametime) but, it does not allow main.js to be executed until both of them are completely loaded.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5aw3luybg0c07vukf2nu.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%2F5aw3luybg0c07vukf2nu.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AMD and Requirejs combination was popular for several years, but did not last because of two reasons:&lt;br&gt;
The syntax of AMD modules was confusing for exporting and importing modules. Further, javascript developers were increasingly using CJS libraries written primarily in Nodejs, such as lodash.&lt;/p&gt;
&lt;h3&gt;
  
  
  CJS modules, browser and bundlers
&lt;/h3&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%2Funapik36gxwju3rtg9i7.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%2Funapik36gxwju3rtg9i7.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
To solve CJS's "sync module load" problem for browsers, some smart developers jumped in and created a build tool named &lt;strong&gt;Browserify&lt;/strong&gt;(2011). Browserify crawls the whole webapp at build time to find all &lt;code&gt;require&lt;/code&gt;s and replaces them with content from the node-module folder(since it runs in build time). At the end of the build we have one single js file containing all the js files.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgox5kvvjuk7ic9n708ii.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%2Fgox5kvvjuk7ic9n708ii.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Browserify allowed frontend developers to write their entire webapp in CJS module format.&lt;/p&gt;
&lt;h3&gt;
  
  
  World of incompatible modules
&lt;/h3&gt;

&lt;p&gt;At this point, developers can choose from a variety of modules and write their projects in one of them. The problem arises when one tries to use a module from another system but the formats are incompatible.&lt;br&gt;
In order to resolve this problem, two solutions were proposed:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Some developers preferred to create a standard module system that works with both nodejs(backend) and browsers(frontend). They introduced the ES module system(2016) but it was not supported by neither Nodejs nor browsers until 2019. &lt;/li&gt;
&lt;li&gt;Some other developers proposed to create a bundler that accepts all types of modules. You probably know it: webpack. Webpack is a swiss army knife which allows developers to write code in multiple module systems (for example, ES and CJS simultaneously). It also provides additional functionalities like asset management, code splitting, tree shaking, etc.&lt;/li&gt;
&lt;/ol&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%2Fiuaslcx2rwoclc9j8420.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%2Fiuaslcx2rwoclc9j8420.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this phase, we have modules which can support encapsulation and provide dependency management, and thanks to webpack we can use our favorite libraries without being worry of incompatibilities. Are we at the end of our journey?&lt;br&gt;
The answer is no. JS world prefers to have a &lt;strong&gt;native&lt;/strong&gt; solution for this incompatibility problem. Wouldn't it be better to have one standard module that doesn't need any extra transpilation system to be understood by browsers and nodes? Remember that webpack's nice features came with a price: complexity. Webpack is difficult to configure even after starting with a zero configuration at version 4.&lt;/p&gt;
&lt;h3&gt;
  
  
  Supporting ES modules and new bundlers
&lt;/h3&gt;

&lt;p&gt;After node v13 and some famouse modern browsers started to support ES modules, more and more developers from both environments started to use ES modules. Even famouse CJS modules like lodash delivered an ES version of their library.&lt;br&gt;
In addition to its standard status, ES is popular for two other reasons: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Its static nature allows for some build-time bundle optimization, such as &lt;a href="https://www.codingame.com/playgrounds/7463/tree-shaking-in-javascript-with-rollup" rel="noopener noreferrer"&gt;tree shaking&lt;/a&gt;. &lt;/li&gt;
&lt;li&gt;The flexibility to define multiple modules in one file (AMD managed to do this, but their implementation had a number of other problems).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It was suggested that since everyone writes their code in ES modules and node and most browsers can resolve es modules, why would we use a complicated bundler like webpack to convert each module type into another? What if we just had a bundler for ES modules?&lt;/p&gt;

&lt;p&gt;This led to the creation of Rollup. The philosophy was:&lt;br&gt;
Since ES modules can be deployed both in browsers and in nodes, this should eliminate the need for unnecessary transformations. Using this approach, Rollup could reduce not only the configuration complexity but also the bundle size as well as the build time.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyji6r4m44j7xy0i1tgq4.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%2Fyji6r4m44j7xy0i1tgq4.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
There is an old saying, "Use Rollup for your libraries and Webpack for your web applications". It's a rule of thumb, and many web apps are bundled with Rollup or vice versa, but what makes Webpack the most appealing choice for building webApps? &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Asset(css, images, font) management features &lt;/li&gt;
&lt;li&gt;Giving developers the flexibility to write their code in the ES modules while importing the CJS libraries like lodash(It is also possible with Rollup but requires plugins). &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;However, Rollup is popular among libraries since it supports a variety of expose formats, including ES, CJS, AMD, and script tags (whereas webpack does not support ES output).&lt;/p&gt;
&lt;h2&gt;
  
  
  Supported ES modules and non-bundlers
&lt;/h2&gt;

&lt;p&gt;After modern browsers began supporting ES modules, a discussion began between two groups of developers:&lt;/p&gt;

&lt;p&gt;Revolutionary developers: Currently, our development team's productivity is negatively affected by bundling. During build time, we spent too much time finding and resolving dependencies. Why not just transpile other popular module formats(CJS) into ES and let the browser resolve and execute them?&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc0akowars4k4x2av8r8s.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%2Fc0akowars4k4x2av8r8s.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Conservative developers: No bundle?! You will have a network request per file which effects your runtime performance.&lt;br&gt;
And would you be able to guarantee that your clients do not use old browsers like IE11(which does not support ES modules)?&lt;/p&gt;

&lt;p&gt;Revolutionary developers: We can't guarantee which browsers our clients use, so we still bundle for our production mode. However, we can ensure that our developers have access to modern browsers so that we can skip bundling in development mode. This is what our proposal looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;production&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Do bundling&lt;/span&gt;
    &lt;span class="c1"&gt;// Do the rest of building tasks&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Do the rest of building tasks&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Conservative developers: ok! Let's give it a try. But we will be careful with that because due to the different build approaches what you see and test in development mode could be different from what you have finally in your production.  &lt;/p&gt;

&lt;p&gt;Vite(pronounced /vit/) and Snowpack were created as a result of this discussion. There are many similarities between them. The big difference is that vite is opinionated. It means you get rid of some configuration but it also reduces your flexibility.&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%2Fp6f8ekjmzub2aj0mdhx4.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%2Fp6f8ekjmzub2aj0mdhx4.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For example Using Vite, your production will use Rollup to bundle, whereas with Snowpack, you can use your choice of bundle (or even leave it unbundled).&lt;/p&gt;

&lt;p&gt;Generally, if you're comfortable with tools such as vue-cli or react-create-app, which set up scafffolding projects with zero config, Vite would be a good choice for you.&lt;/p&gt;

&lt;p&gt;It seems interesting for me as a Vue developer who does not like to set up a project from scratch with its build tool. But before using Vite for development, you should be aware of some aspects.&lt;/p&gt;

&lt;p&gt;Until recently, Vite had no official support for legacy browsers. To put it simply: Vite's created bundles didn't work with IE11. Currently, it is supported by an official plugin named: plugin-legacy.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fymjd31gupokgvrzp53l4.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%2Fymjd31gupokgvrzp53l4.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Another fact to know is that using Vite you can import CJS dependencies in ES modules, but in some cases, it may not work quite as expected.&lt;/p&gt;

&lt;h3&gt;
  
  
  esbuild
&lt;/h3&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%2Fuq7xpq3i6bsuefhpufkn.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%2Fuq7xpq3i6bsuefhpufkn.png" alt="from esbuild website. the time to do a production bundle of 10 copies of the three.js library from scratch using default settings, including minification and source maps"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Esbuild is an impressively fast bundler based on Go, which many think &lt;strong&gt;will be the most used bundler for big applications in the future&lt;/strong&gt;. esbuid's problem is its small community team and the fact that it is not production-ready. Some features like dev server is missing but you can use the combination of Snowpack and esbuild.&lt;br&gt;
Furthermore, Vite documentation indicates that esbuild would be preferred over or in addition to Rollup when esbuild became production 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%2Fink1u3wdo2srpbjidyfr.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%2Fink1u3wdo2srpbjidyfr.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  History overview
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9jp1xt0p363t1fov2px2.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%2F9jp1xt0p363t1fov2px2.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Request
&lt;/h2&gt;

&lt;p&gt;I am so interested to see which module system and build tool you use/have used for your projects. Drop a comment below and let's talk about it. &lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.javascripttutorials.net/unbundling-the-javascript-module-bundler/" rel="noopener noreferrer"&gt;Unbundling the JavaScript Module Bundler&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://addyosmani.com/writing-modular-js/" rel="noopener noreferrer"&gt;Writing Modular JavaScript With AMD, CommonJS &amp;amp; ES Harmony&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.google.com/amp/s/auth0.com/blog/amp/javascript-module-systems-showdown/" rel="noopener noreferrer"&gt;Java Script Module Systems Showdown&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://benmccormick.org/2015/05/28/moving-past-requirejs" rel="noopener noreferrer"&gt;Moving Past RequireJS&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://requirejs.org/docs/whyamd.html" rel="noopener noreferrer"&gt;Why AMD&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://css-tricks.com/comparing-the-new-generation-of-build-tools/" rel="noopener noreferrer"&gt;Comparing the New Generation of Build Tools&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/@PepsRyuu/why-i-use-rollup-and-not-webpack-e3ab163f4fd3" rel="noopener noreferrer"&gt;Why I Use Rollup And Not Webpack&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://peterxjang.com/blog/modern-javascript-explained-for-dinosaurs.html" rel="noopener noreferrer"&gt;Modern JavaScript Explained for Dinosaurs&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Real world example of compose function and currying.</title>
      <dc:creator>Pegah Safaie</dc:creator>
      <pubDate>Thu, 22 Apr 2021 18:00:09 +0000</pubDate>
      <link>https://dev.to/pegahsafaie/real-world-example-of-compose-function-and-currying-3ofl</link>
      <guid>https://dev.to/pegahsafaie/real-world-example-of-compose-function-and-currying-3ofl</guid>
      <description>&lt;h2&gt;
  
  
  Another currying article
&lt;/h2&gt;

&lt;p&gt;Using Javascript, you can decide to write your code based on FP or OOP principles. When you decide on FP there are some concepts you need to understand in order to make the most out of FP principles. These include concepts like currying and compose functions. For me it took a while to understand what the &lt;strong&gt;currying&lt;/strong&gt; is and &lt;strong&gt;when&lt;/strong&gt; and &lt;strong&gt;how&lt;/strong&gt; I should use it in my code. Here, I tried to explain what I found in a simple way, hopping to make the learning process quicker and smoother for you.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When to use compose functions?&lt;/li&gt;
&lt;li&gt;How to use compose functions?&lt;/li&gt;
&lt;li&gt;How to enhance compose functions using currying?&lt;/li&gt;
&lt;li&gt;Homework&lt;/li&gt;
&lt;li&gt;Your opinion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt;When should we use compose functions in our code?
&lt;/h2&gt;

&lt;p&gt;we want to model the following ice cream production line by using javascript functions.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6pb168ls15vhgxrv1rn3.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%2F6pb168ls15vhgxrv1rn3.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We see a sequence of 3 actions following one another: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mix&lt;/strong&gt; the ice cream with sth like 🍓, 🍒 and 🍇.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decorate&lt;/strong&gt; the ice cream with sth like 🍫.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Form&lt;/strong&gt; the ice cream scoopes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All actions take ice cream as input, modify it with some settings(berries or chocolate) and send the modifed ice cream to the ouput to be used by next function.&lt;/p&gt;

&lt;p&gt;Here is the atomic function for each action.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;mix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tastes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;tastes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&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="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;ice&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;decorate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;taste&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;decorated with &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;taste&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;form&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ice&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scooped &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;ice&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 a berry ice cream with chocolate topping, you might write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt; &lt;span class="nf"&gt;decorate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;form&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;🍓&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;🍒&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;🍇&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="err"&gt;🍫&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="c1"&gt;// output: " scooped 🍓, 🍒, 🍇 ice cream decorated with 🍫"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm sure you've seen this pattern in your code: &lt;br&gt;
Modifying a single data (ice cream) by a couple of operations to create the desired outcome (scooped berry ice cream with chocolate). &lt;br&gt;
But this way of writing function sequences is not quite nice. The brackets are too many, and the execution order is from right to left.&lt;br&gt;
To write it better, we can use the &lt;strong&gt;Composition Function&lt;/strong&gt; concept in math:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Having &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;f: x -&amp;gt; y&lt;/li&gt;
&lt;li&gt;g: y -&amp;gt; z&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;we can create a third function which receives a single input(x) and creates an output(z)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;h: x -&amp;gt; z&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;it looks like &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;h(x) = g(f(x))&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt;3 steps to write a better function sequence using the composition function in JS
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Create a new compose function&lt;/strong&gt;&lt;br&gt;
For me the simplest compose function would be a wrapper function, which receives all required inputs and returns the results of the function sequence execution. &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2otthyirnkegrgafhs9e.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%2F2otthyirnkegrgafhs9e.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;compose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tastes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;decorateTaste&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;form&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;decorate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tastes&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;decorateTaste&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// call compose&lt;/span&gt;
&lt;span class="nf"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ice&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;🍓&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;🍒&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;🍇&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;🍫&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// output: " scooped 🍓, 🍒, 🍇 ice cream decorated with 🍫"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Reduce the compose function's input parameters&lt;/strong&gt;&lt;br&gt;
Compose function should take only one single input. This is the data that gets modified throught the function sequence and comes out as output. In our example ice cream is this data.&lt;br&gt;
It matters to keep compose function unary because when calling compose function we only want to focus on the data that is sent to the method and not care about the setting parameters.&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%2F6n8qbpddt03urr3jjre4.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%2F6n8qbpddt03urr3jjre4.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
As you see in the above picture, Each action(mix, decorate) can be customized by its corresponding setting parameters(berries and chocolate):&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;// Customized version of mix function using berries&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mixWithBerries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ice&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;mix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ice&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;🍓&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;🍒&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;🍇&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="c1"&gt;// Customized version of decorate function using chocolate&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decorateWithChoclate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ice&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;decorate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ice&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;🍫&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Compose function accepts just one single input&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;compose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ice&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;form&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;decorateWithChoclate &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mixWithBerries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ice&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;

&lt;span class="c1"&gt;// Call compose. looks nicer!&lt;/span&gt;
&lt;span class="nf"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. A more elegant generic way of creating compose functions&lt;/strong&gt;&lt;br&gt;
In this section we write a compose function &lt;strong&gt;generator&lt;/strong&gt;. Why? Because it is more convenient to use a compose function generator rather than to write a compose function every time if you use compose functions a lot.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can skip this section if you want to use composeGenerator function available in lodash/fp and ramda libraries.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We also implement our compose function generator in a more elegant fashion than our previous implementation of compose function, where we still have a lot of brackets and the execution order is still from right to left.&lt;/p&gt;

&lt;p&gt;Then compose function generator is a function that takes a series of functions(fn1, fn2, ..., fnN) as input parameters and returns a new function(compose).  The returned compose function receives data and executes functions(fn1, fn2, ..., fnN) in a given order.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm0kpy0pmqluo8an4c3af.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%2Fm0kpy0pmqluo8an4c3af.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
That looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;composeGenerator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fn2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fn3&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;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;fn1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fn2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fn3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="c1"&gt;// create compose function using composGenerator&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;compose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;composeGenerator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;decorate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ice&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&lt;/span&gt;
&lt;span class="nf"&gt;composeGenerator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;decorate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mix&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The double arrow in the code above indicates a function &lt;code&gt;composegenerator(fn1, fn2, fn3)&lt;/code&gt; which returns another function &lt;code&gt;compose(data)&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;This implementation of composeGenerator is limited to 3 functions. We need something more generic to compose as many functions as you want:&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;composeGenerator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;fns&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;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
    &lt;span class="nx"&gt;fns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduceRight&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="nx"&gt;fn&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;fn&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="nx"&gt;data&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;compose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;composeGenerator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;decorateWithBerries&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mixWithChoclate&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ice&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&lt;/span&gt;
&lt;span class="nf"&gt;composeGenerator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;decorateWithBerries&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mixWithChoclate&lt;/span&gt; &lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's not easy but at least you define it once, and then you don't have to worry about the complexity anymore. Let's break it down into a group of smaller parts to make it easier to understand.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fznabbmv0vk55l58y6pph.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%2Fznabbmv0vk55l58y6pph.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
And here is how reduceRigth works when we call composeGenerator with our piepeline functions.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7cwuo3mxsxc6oh5urbmq.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%2F7cwuo3mxsxc6oh5urbmq.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt;Enhance your compose function with currying
&lt;/h2&gt;

&lt;p&gt;Our solution to remove the setting parameter from our compose function is not good since we will have to write new custom function every time we wish to add a new flavor to our pipeline:&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;// Change the production line to decorate with 🍓&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decorateWithStrawberry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ice&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;decorate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ice&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;🍓&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nf"&gt;composeGenerator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;decorateWithStrawberry&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mixWithChoclate&lt;/span&gt; &lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Change the production line to decorate with 🍓 and 🍫&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decorateWithChocAndStrawberry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ice&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;decorate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ice&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;🍓&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;🍫&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="nf"&gt;composeGenerator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;decorateWithChocAndStrawberry&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mixWithChoclate&lt;/span&gt; &lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our solution is to implement the &lt;strong&gt;curry&lt;/strong&gt; function, which accepts the tastes and returns the decorate function with one single argument.&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;// Currying decorate function&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;curriedDecorate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tastes&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;ice&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;decorate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tastes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Currying mix function&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;curriedMix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;taste&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;ice&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;decorate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;taste&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;composeGenerator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="nf"&gt;curriedDecorate&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="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="nf"&gt;curriedMix&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="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="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="nx"&gt;ice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk8iny4c9a7pbyo19ih8f.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%2Fk8iny4c9a7pbyo19ih8f.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Like compose functions, we may write our curried functions ourselves or create a generic function that returns a curried version of a function.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can skip this section if you want to use curry function available in lodash/fp and ramda libraries.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A curry function receives a function &lt;code&gt;fn&lt;/code&gt; as input. If the passed arguments(&lt;code&gt;args.length&lt;/code&gt;) are at least equal to the function &lt;code&gt;fn&lt;/code&gt;'s required arguments(&lt;code&gt;fn.length&lt;/code&gt;), it will execute function &lt;code&gt;fn&lt;/code&gt;, otherwise it will return a partially bind callback.&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;curry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fn&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; 
            &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; 
            &lt;span class="nx"&gt;currify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nf"&gt;curry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decorate&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="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="p"&gt;])&lt;/span&gt; &lt;span class="c1"&gt;//output: a function which just needs ice cream as input&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we execute a curryFunction(curriedDecorate) with all the setting parameters(decorateTaste), it returns a new function which only needs one data parameter, and we can use it in our compose function.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt;A homework for you:
&lt;/h2&gt;

&lt;p&gt;Generally, remember that currying is used to decrease the number of parameters of a function. In our last example, we saw that reducing inputs to a single one can be beneficial when using a compose function but unary functions can be used in more cases where we only require a single argument. For example in arrow functions we can remove the brackets when function just has one parameter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 👎&lt;/span&gt;
&lt;span class="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;3&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;digit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;digit&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&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;3&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;digit&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;digit&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a pratice try to improve this code using currying.&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;pow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;exponent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;exponent&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;digits&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;3&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;exponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;digits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;digit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;digit&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;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;digit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;exponent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;you can find the solution in this &lt;a href="https://www.youtube.com/watch?v=fvJ9yWqXcZI" rel="noopener noreferrer"&gt;video&lt;/a&gt; from Derick Bailey&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt;Your opinion
&lt;/h2&gt;

&lt;p&gt;What is your favorite example of using currying in your code? And generally do you like using it or do you think it makes the code unnecessarily complicated ?&lt;/p&gt;

</description>
      <category>functional</category>
      <category>currying</category>
      <category>composition</category>
      <category>javascript</category>
    </item>
    <item>
      <title>You need types; but not necessarily typescript.</title>
      <dc:creator>Pegah Safaie</dc:creator>
      <pubDate>Sun, 21 Mar 2021 21:52:38 +0000</pubDate>
      <link>https://dev.to/pegahsafaie/you-need-types-but-not-necessarily-typescript-5e23</link>
      <guid>https://dev.to/pegahsafaie/you-need-types-but-not-necessarily-typescript-5e23</guid>
      <description>&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;There are many good reasons why you might not be a fan of adding typrscript to your project: migration cost, additional transpiling step, or lack of knowledge.&lt;br&gt;
On the other hand we cant overlook the advantages of typing like validation, problem detection at compile time and better debugging experience.&lt;br&gt;
&lt;a href="https://dev.to/puruvj/using-typescript-without-typescript-3pke"&gt;This article&lt;/a&gt; shows how the combination of VSCode + ESLint + &lt;strong&gt;JSDOC&lt;/strong&gt; allows you to type your project without using typescript. I created a small JS sample &lt;a href="https://github.com/pegahsafaie/js-with-typing"&gt;project&lt;/a&gt; with a practical readme to play around with this concept.&lt;/p&gt;

&lt;p&gt;What I like best about this approach is that you can gradually introduce typing into your project without the need for any extra transpilation step in build or configuration boilerplates in the project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirement
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;VSCode IDE&lt;/li&gt;
&lt;li&gt;ESLint extension installed and enabled.&lt;/li&gt;
&lt;li&gt;You must be familiar with JSDoc. Maybe you already used it but did not know its name 😉&lt;/li&gt;
&lt;li&gt;A little bit! understanding of typing&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Explain the project
&lt;/h2&gt;

&lt;h4&gt;
  
  
  What is our goal?
&lt;/h4&gt;

&lt;p&gt;We have a small simple JS project and we want to add typing advantages to that without using typescript. These advantages are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We want VSCode to show us intelligent code completion, hover info, and signature information.&lt;/li&gt;
&lt;li&gt;We want to detect the potential bugs while writing the code, not during runtime.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  What is our plan?
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Review our JS code to find potential problems caused by lack of typings. &lt;/li&gt;
&lt;li&gt;Add JSDoc documentation to our JS files and enable the eslint plugin to see how that changes things. &lt;/li&gt;
&lt;li&gt;We will also go over some advanced typing features, such as custom types, imports and unions. Check out the &lt;a href="https://github.com/pegahsafaie/js-with-typing"&gt;GitHub repository&lt;/a&gt; for more examples of inheritance, declaration files and modifiers. &lt;/li&gt;
&lt;li&gt;Finally, we will talk about the challenges we might face using this approach.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Start
&lt;/h4&gt;

&lt;p&gt;Our project consists of a number of utils functions(left), and a main file(right) that uses them.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SEdBtxJz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c3jms14w7zfg1nlowsvi.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SEdBtxJz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c3jms14w7zfg1nlowsvi.jpg" alt="Alt Text" width="880" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;See any problems? Yes! Did eslint or vsCode complain? Not yet!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EUC2F311--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0r9v1l10clpqfa3nep8r.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EUC2F311--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0r9v1l10clpqfa3nep8r.jpg" alt="Weak JS typing issues" width="880" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OK! time to fix them in two steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Adding JSDoc to the util methods.&lt;/li&gt;
&lt;li&gt;Telling ESLint to be strict with the main.js file!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6_2nk89p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9fk1jbd7tisq13akwydt.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6_2nk89p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9fk1jbd7tisq13akwydt.jpg" alt="Adding JSDoc to the util methods" width="753" height="923"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Still no errors from IDE or ESLint, but autocompleting works now.&lt;/p&gt;

&lt;p&gt;Now add // @ts-check to the top of the main.js file and you should see errors appearing. Although &lt;code&gt;isPositive&lt;/code&gt; doesn't report any errors, using autocomplete we can see the output which is a string and we can therefore avoid the bug.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qgoRKZQX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/19w71i5tprg26gm8icly.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qgoRKZQX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/19w71i5tprg26gm8icly.jpg" alt="Alt Text" width="880" height="646"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q&lt;/strong&gt;: Is it possible to define our own custom types? Sure we can, with &lt;a class="mentioned-user" href="https://dev.to/typedef"&gt;@typedef&lt;/a&gt; annotations of JSDoc. Let's see how. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;using &lt;code&gt;@typedef&lt;/code&gt; we define a new type named &lt;code&gt;Animal&lt;/code&gt; with two properties.&lt;/li&gt;
&lt;li&gt;using &lt;code&gt;@type&lt;/code&gt; we assign this type to a variable.
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rsZGeWhB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qavkkw4e73jwy7rycxrh.jpg" alt="Define and use custom types" width="880" height="486"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Q&lt;/strong&gt;: Can we use the same type in multiple places? Like we use modules to organize our code? Yes! We can do it by using @import and here's how:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uZ1Y0Od1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/am85d1wrd0bf2b262mog.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uZ1Y0Od1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/am85d1wrd0bf2b262mog.jpg" alt="Alt Text" width="880" height="414"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If someone changes the &lt;code&gt;race&lt;/code&gt; property to &lt;code&gt;type&lt;/code&gt; in the future, our JSDoc annotations help him to see the side effect and fix it!&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7KLRuUj1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/48f64vx6n32uwvpiyteg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7KLRuUj1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/48f64vx6n32uwvpiyteg.jpg" alt="Alt Text" width="880" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Animal&lt;/code&gt; type can be defined once at the top of a file and be used many times there afterwards.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hQ16_59M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6zzveuy9oy7x9eff8a12.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hQ16_59M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6zzveuy9oy7x9eff8a12.jpg" alt="Alt Text" width="747" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The challenges of moving to JSDoc:
&lt;/h2&gt;

&lt;p&gt;Enough talking through the flowers. Things are not always so easy as they are discussed here.&lt;br&gt;
&lt;strong&gt;Learning Curve:&lt;/strong&gt; By complicated typings, you will still need to know about typing concepts and learn JSDoc syntax.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Organizing&lt;/strong&gt; : Organizing your JSDocs and avoiding duplication. (JSDoc can tie into the modules concept)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Maintenance&lt;/strong&gt;: Think of JSDoc as some meta data that needs maintenance. If people don't care, and no longer update it as they make changes, there is no benefit to that. Maybe you should include it in your MR process and ask reviewers to double check it.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;JSDOC cheat sheet: &lt;a href="https://devhints.io/jsdoc"&gt;https://devhints.io/jsdoc&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mobiquity.com/insights/typescript-to-javascript-with-jsdoc-and-back"&gt;https://www.mobiquity.com/insights/typescript-to-javascript-with-jsdoc-and-back&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/puruvj/using-typescript-without-typescript-3pke"&gt;https://dev.to/puruvj/using-typescript-without-typescript-3pke&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>jsdoc</category>
      <category>typescript</category>
      <category>vscode</category>
    </item>
    <item>
      <title>These decision trees help you to create your first website.</title>
      <dc:creator>Pegah Safaie</dc:creator>
      <pubDate>Mon, 08 Mar 2021 11:35:05 +0000</pubDate>
      <link>https://dev.to/pegahsafaie/decision-trees-helped-me-to-create-my-portfolio-1ndc</link>
      <guid>https://dev.to/pegahsafaie/decision-trees-helped-me-to-create-my-portfolio-1ndc</guid>
      <description>&lt;p&gt;As a frontend developer, people expect me to be good and proficient at building websites. But I am not. I decided to change this, so I started creating my own Portfolio.&lt;/p&gt;

&lt;p&gt;Initially I looked for tutorials showing me the general path from a dev point of view but what I found were either too tech specific like 'How to develop website with x and y technologies' or some others articles like 'how to create a website without coding'.&lt;/p&gt;

&lt;p&gt;That's how I came up with my own set of decision trees!&lt;/p&gt;

&lt;h2&gt;
  
  
  First stop: Draw what you want to see at the end
&lt;/h2&gt;

&lt;p&gt;Draw the layout of each page of your website. Think about the user's navigation, positioning and content but ignore details such as styles, colors and fonts.&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%2Flxq0oylbkhy0n08ew951.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%2Flxq0oylbkhy0n08ew951.png" alt="A portfolio wireframe sample. Wireframes are the the skleton of your website"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Don't underestimate this step as it will get you deeper into your project requirements and help you discover issues from the very beginning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Second stop: Are you a designer?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiarcemwsl3s0354ge0pe.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%2Fiarcemwsl3s0354ge0pe.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Templates are the best way to go If you don't need a custom website. They're well-designed and well-organized and save your time.  You can even find templates in your favorite CSS frameworks.&lt;br&gt;
&lt;a href="https://themeforest.net" rel="noopener noreferrer"&gt;Theme Forest &lt;/a&gt; prices start from 2$&lt;br&gt;
&lt;a href="https://www.free-css.com" rel="noopener noreferrer"&gt;Free CSS and HTML templates&lt;/a&gt;&lt;br&gt;
&lt;a href="https://jamstackthemes.dev/theme/#ssg=eleventy" rel="noopener noreferrer"&gt;Jamstack template website&lt;/a&gt; Choosing your stack it gives you a starter theme✨.&lt;br&gt;
&lt;a href="https://css-tricks.com/front-end-challenges/" rel="noopener noreferrer"&gt;CSS challenge websites&lt;/a&gt; Get the idea and implement your CSS &lt;/p&gt;

&lt;p&gt;To find a website designer, it's always best to ask your (social)friends. You can also hire a freelancer through &lt;a href="https://www.fiverr.com/" rel="noopener noreferrer"&gt;Fiverr&lt;/a&gt; or &lt;a href="https://www.freelancer.com" rel="noopener noreferrer"&gt;Freelancer&lt;/a&gt;. I also search in &lt;a href="https://www.figmacrush.com/figma-website-templates/" rel="noopener noreferrer"&gt;Figma&lt;/a&gt; and &lt;a href="https://www.sketchappsources.com/tag/web.html" rel="noopener noreferrer"&gt;Sketch&lt;/a&gt; communities to see work samples of designers. If you like their work, you may contact them directly .&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To communicate with your designer&lt;br&gt;
    1. Prepare first draft of your website skeleton. &lt;br&gt;
    2. Inform your designer If you prefer to receive CSS in a specific framework (Tailwind, material, ...).&lt;br&gt;
    3. Prepare a list of your favorite websites in your scope.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Third stop: Select your static tech stack
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foo0w1474mhm40pwf2yos.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%2Foo0w1474mhm40pwf2yos.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Understanding your content and its updating behavior plays an important role in technologies you choose. If you are the only one updating the website from time to time, put all the content in HTML and ignore the CMS topic, but if you have a non-technical person updating the content, you should choose a CMS for your website.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Traditional CMS vs headleass CMS:&lt;br&gt;
&lt;strong&gt;traditional CMS&lt;/strong&gt; platforms allow non-technical users to create entire website without coding. Selecting template, adding plugins and modifying content all happens in one place. A disadvantage? You are limited to this platform. You can't integrate custom code and functionality to your website. &lt;br&gt;
Using &lt;strong&gt;Headless CMS&lt;/strong&gt;, non technical users still receive a dashboard for easy content creation.  However this's it. The rest of site creation is handled by developers calling APIs(REST,GraphQL) to access the content.&lt;a href="https://jamstack.org/headless-cms/" rel="noopener noreferrer"&gt;List of headless CMS for Jamstack sites&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once you've decided on your content, it's time to think about optimization and SEO. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;SSG or Static Site Generators:&lt;br&gt;
 You decided to fetch your content using APIs. Nice! But it also means your users have to wait for your content to be fetched! Search engines crawlers are even less patient and just ignore your content when they see an asyncronous API call.&lt;br&gt;
 Solution? Using SSGs, you can fetch your content in build time and put it in your templates. &lt;br&gt;
Here is a &lt;a href="https://jamstack.org/generators/" rel="noopener noreferrer"&gt;List of SSGs for Jamstack sites&lt;/a&gt;. Remember that SSG frameworks can add boilerplate and complexity to your project. If you don't need their features use simpler ones such as 11ty and Jekyll.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Finaly the last part of decision tree belong to our lovely frameworks and libraries.&lt;br&gt;
Do not use frameworks for small simple websites like portfolios. Frameworks add complexity and boilerplate to your website. In many cases a light DOM manipulator like JQuery is all you will need. Although you may not use frameworks, you may still require modules (for example if you would use npm packages). If you use modules in your code, you will also need a module bundler. In most JS frameworks, the bundler is provided and configured by default. But if you don't use a framework, you may need to do it manually. Make sure to not underestimate the amount of time it will take.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fourth stop: Contact form
&lt;/h2&gt;

&lt;p&gt;The contact form is a must have feature for your Portfolio. &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7akbhf27dvutc8gvuvv2.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%2F7akbhf27dvutc8gvuvv2.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use &lt;a href="https://www.emailjs.com/docs/introduction/how-does-emailjs-work/" rel="noopener noreferrer"&gt;EmailJS&lt;/a&gt; as a client solution with a generous free tier. If you do not have module bundler in your project, use browser script instead of the npm package.&lt;/p&gt;

&lt;p&gt;If you are thinking about implementing your own email service, don't forget about serverless functions as an alternative to building server.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Serverless functions give you all the power of a traditional server app while eliminating the headache of routing, deployment and scaling. Because of this, they're an attractive choice for client developers. The word serverless doesn't mean that there is no server, but that you don't need to think about a permanently up and running server.&lt;br&gt;
&lt;a href="https://medium.com/@houdinisparks/serverless-faas-eg-aws-lambda-vs-paas-eg-azure-web-apps-ca0e7146b1c4" rel="noopener noreferrer"&gt;This article&lt;/a&gt; compares serverless functions with classic server apps.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Final: Hosting
&lt;/h2&gt;

&lt;p&gt;There are many hosts with generous free plans that you can choose from. To avoid confusion, create a matrix for yourself. The vertical axis identifies features you should compare and the horizontal axis names the hosts.&lt;br&gt;
My sample matrix for the free tier looks like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Heroku&lt;/th&gt;
&lt;th&gt;Vercel&lt;/th&gt;
&lt;th&gt;Firebase&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;static website&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nodejs&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ssl&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;custom domain&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;easy deploy&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Hosting providers give you a generic domain name like websitename.hostname.---&lt;br&gt;
For a nice looking domain name, buy it separately and add it as a custom domain to your host.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  An unexpected sweet conclusion
&lt;/h2&gt;

&lt;p&gt;After finishing this article I just realized that all the decisions we made here led us to the Jamstack approach🍯! to understand Jamstack, I invite you through a discussion I had with myself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wise Me: In Jamstack approach, client devs don't write any server code. They call APIs when a dynamic content or server functionality is needed.&lt;/li&gt;
&lt;li&gt;Stupid Me: Common! It has been a long time since we have separated client and server projects that communicate through APIs. You just gave it a trendy name.&lt;/li&gt;
&lt;li&gt;Wise me: The new trend is not just about separated client and server projects but rather about 3rd party services that offer a wide range of backend functionalities from authentication to API definition. Using them, a client dev can easily develop a web project from scratch without the help of a server dev. For more customized backend functionality, client devs can use serverless functions.&lt;/li&gt;
&lt;li&gt;Stupid Me: Got it. You deliver your projects with fewer experts and infrastructures in less time. Are they expensive?&lt;/li&gt;
&lt;li&gt;Wise Me: You pay based on your scale. When you have a low traffic website, you don't pay but when your website becomes famous and you get more visitors and customers, you start paying.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>PWA for Vue applications: A practical guide</title>
      <dc:creator>Pegah Safaie</dc:creator>
      <pubDate>Tue, 23 Feb 2021 14:28:08 +0000</pubDate>
      <link>https://dev.to/pegahsafaie/pwa-for-vue-applications-a-practical-guide-4de3</link>
      <guid>https://dev.to/pegahsafaie/pwa-for-vue-applications-a-practical-guide-4de3</guid>
      <description>&lt;h2&gt;
  
  
  Table Of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What is PWA?&lt;/li&gt;
&lt;li&gt;Fast decoration of your app using PWA Vue CLI plugin&lt;/li&gt;
&lt;li&gt;
Get deeper on caching

&lt;ul&gt;
&lt;li&gt;How does caching affect "reach offline exprience" of my page?&lt;/li&gt;
&lt;li&gt;Customize Vue CLI PWA plugin to support API caching&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is PWA?&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Consider the PWA as ice toppings that you can add to your Web App. Each topping is different but by blending them together they turn your Web App into one that tastes exactly like a native app. These flavors have always been available, but Google's chefs put them all together in one tray and called them Progressive Web Apps or PWA!&lt;br&gt;
They even introduced the Lighthouse taster that lets us know how well our web app tastes like a PWA (or better yet, how well it tastes like a native App).&lt;br&gt;
Many apps since then have added these toppings or parts of them to their websites. Some of the most famous ones are Spotify, Housing, and Starbox.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do you need PWA tray?&lt;/strong&gt; &lt;br&gt;
In order to reply to this question, you need to know more about the toppings available in the PWA tray along with your customers preferences. If your customers don’t like strawberries in their ice cream, why would you pay for one?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;🍓 Reach  offline  experience: This means your app is available and fast even if the internet connection fails. If your web app is on the intranet, no one will care about this topping. However, people who live in developing countries and users who access your website on their mobile phones may very well value this topping.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;🍯 Installable: Installable apps are'nt just accessible via a URL in the browser, but also  can be  installed on android and  ios  devices.In this case users will click on an icon to open your app instead of writing the URL in the browser. That's it! You don't have to re-write your app in native or electron.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;🍒 Background sync: A Background sync feature lets you defer the actions if the user doesn't have a reliable connection. Imagine that your user fills out a form and presses 'Send'. But there is no connection currently. You don't want his efforts go to waste, so you gather the actions and send it to server as soon as the connection is back.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;🍇 push notification: What do you think about mobile app notifications, especially when they're closed? For instance: when you're watching TV and you're receiving a notification from the twitter app, saying: "Hey, somebody gave you a 👍. If you think it's a good idea to notify your users, then the Push notification feature might suit you.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;How much time and effort should I spend on this tray?&lt;/strong&gt;&lt;br&gt;
When using PWA plugins, you can dramatically improve your PWA factor within 30 minutes. After that, it gets exponentially harder to make it better.&lt;/p&gt;
&lt;h2&gt;
  
  
  Fast decoration of your App using PWA Vue CLI plugin 🍓🍯&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I hope you already know about  Vue  CLI plugins. But  don't  worry if you don't. They're pretty easy to understand.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Vue CLI is a npm package you install globally on your computer.&lt;br&gt;
It lets you set up Vue projects quickly and without headaches.&lt;/p&gt;

&lt;p&gt;Vue CLI Plugins are npm packages you add as dependency to your Vue CLI project,&lt;br&gt;
They add some features and functionalities to your Vue project quickly and without headaches. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here we use &lt;a class="mentioned-user" href="https://dev.to/vue"&gt;@vue&lt;/a&gt;/cli-plugin-pwa to add "🍓Reach offine  experience" and "🍯Installable" support to our web app. That’s important to know: you don’t necessarily need a plugin to add  PWA  support, but using a plugin will make this process faster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Preparation&lt;/strong&gt;&lt;br&gt;
I use a simple Vue CLI project for this article. You can find it &lt;a href="https://github.com/pegahsafaie/vue-cli-PWA-plugin" rel="noopener noreferrer"&gt;here&lt;/a&gt; but you can use any other Vue CLI project of your choice. If you don't know how to create a Vue CLI project look at this &lt;a href="https://cli.vuejs.org/guide/creating-a-project.html#vue-create" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Measure the PWA of your webpage before any changes&lt;/strong&gt;&lt;br&gt;
Before we make any changes let's see what does Google's taster says about us. I recommend you use Incognito, but Chrome or  Firefox works too.&lt;br&gt;
Before running Lighthouse tests on our web app, you have to deploy your app first:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Build your web app in production mode using:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt; npm run build
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;This command will generate a build directory named (by default) &lt;em&gt;dist&lt;/em&gt;.&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;To run dist folder locally on a HTTP-server, Install the HTTP-server on your machine:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt; npm install -g serve
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Now run the server with placing the build directly(dist) on the server:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt; serve -s dist
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;During development you'll be able to use service worker through &lt;code&gt;localhost&lt;/code&gt;, but to deploy it on a site you'll need to have HTTPS setup on your server.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Open the website in your localhost and go to devTools&amp;gt;Lighthouse. Select the "Progressive Web App" category and press 'Generate new report'. That's what you probably see after some minutes.
&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%2Fglcgsre9aturjp1cmb45.jpg" alt="PWA report before applying PWA plugin on my webpage"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Apply PWA Plugin&lt;/strong&gt;&lt;br&gt;
If you are using Git, clean your local changes (commit, stash or discard them). This way you are able to see the changes that were added by the plugin.&lt;/p&gt;

&lt;p&gt;To install and invoke PWA Vue CLI plugin execute this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt; vue add pwa
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Measure Again&lt;/strong&gt;&lt;br&gt;
 Build your app again in production mode and deploy it locally. Now we can ask Mr. Taster about the PWA factor.&lt;br&gt;
 &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foc90scztfk0zi2ozvddz.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%2Foc90scztfk0zi2ozvddz.jpg" alt="PWA report before applying PWA plugin on your webpage"&gt;&lt;/a&gt;&lt;br&gt;
Congrats! It means that your app works offline and you can register it on "App store" or "Google play store". Take a Look at this &lt;a href="https://css-tricks.com/how-to-get-a-progressive-web-app-into-the-google-play-store/" rel="noopener noreferrer"&gt;article&lt;/a&gt; on how to get progressive web app into the google play store.&lt;/p&gt;
&lt;h2&gt;
  
  
  Get deeper&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;When I first applied PWA plugin to my app, I didn't have a good feeling about it. Even after receiving a Lighthouse taster award, My app was performing well without me knowing how. I wasn't even asked to config it during the installation process.&lt;/p&gt;

&lt;p&gt;That's because the plugin does not aim to confuse you with PWA concepts but instead applies proven best practices that most web applications should follow. It assumes that if you know a lot about PWA configuration, you'll return to do your customizations.&lt;/p&gt;

&lt;p&gt;With this section we go one level deeper to see how these best practices can be customized to meet your needs.&lt;/p&gt;
&lt;h4&gt;
  
  
  How does default caching affect my app? &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;As said before, "Reach Offline Experience" on a website means that it is fast and accessible even with an unreliable connection. &lt;br&gt;
Service Workers are the heart and soul of this feature. A service worker is a script that runs independently from your webpage and acts as an interconnect between your website and network, implementing caching strategies to reduce traffic between the webpage and server.&lt;/p&gt;

&lt;p&gt;This diagram below illustrates you how the service worker caches your essential static resources. The essential static resources are the resources that your webpage requires in order to be  initiated. For example html, js,  css  and image files used in your home page are essential resources for your webpage.&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%2F63h0qnc6amnb1d7hpyeg.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%2F63h0qnc6amnb1d7hpyeg.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This process is also logged to your console. Don't be confused with the word workbox. It is a webpack plugin used by your serviceworker to complete the precaching process. Let's learn more about it later on.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiy95nizybqq1kopmioqw.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%2Fiy95nizybqq1kopmioqw.jpg" alt="Consolelog shows us how precaching works"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looking at the application tab of your browser, you see all the precached resources. &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8jjqxvjy1rtzkf4j7bp6.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%2F8jjqxvjy1rtzkf4j7bp6.jpg" alt="PWA webpages cache the essential resources. We can see the list in application tab"&gt;&lt;/a&gt;&lt;br&gt;
Caching worked fine. But let's see how does caching affect the speed of your webpage?&lt;br&gt;
When we refresh the page here is what happens:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvaf4mzhigy9rzbh51kup.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%2Fvaf4mzhigy9rzbh51kup.png" alt="How does caching avoid unnecessary network communication"&gt;&lt;/a&gt;&lt;br&gt;
I refreshed both the PWA and non PWA webpages in 3 different network modes. You can see the differences in network tab in the next pictures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Refreshing without throttleing. The PWA webpage reads from the cache while the non PWA webpage downloads all the resources again. Still you don't see a big time difference in load time as the webpage is small and internet connection is pretty good.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fruyiopothf9yvicpf2g0.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%2Fruyiopothf9yvicpf2g0.jpg" alt="Refresh without throttling"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;By refreshing with slow 3G the load time difference is 2 times bigger.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foslklkphjsday9rfwl1v.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%2Foslklkphjsday9rfwl1v.jpg" alt="Refresh with slow 3G"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rereshing while offline does not load anything for non PWA webpage. The PW webpage on the other hand is loaded smoothly and fast.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F518es4xey52pb2oclrl1.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%2F518es4xey52pb2oclrl1.jpg" alt="Refresh without connection"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see, with a PWA, there isn’t much difference between the three modes. That indicates this website is quite reliable even when the network is not stable.&lt;/p&gt;
&lt;h4&gt;
  
  
  Customize Vue CLI PWA plugin to support API caching&lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;It's important to know what the PWA plugin does before we customize our application. Once you activate the plugin, it registers serviceworker.js in your main file. Registering serviceworker from the main file means we want serviceworker to get registered as soon as the page loads. Apart from that, PWA plugin does'nt do much more than organizing! Whenever the project is built, the PWA plugin tells Workbox to generate a serviceworker to cache the static resources. Workbox is the heart of caching strategies. Two modules in Workbox webpack plugins are responsible for implementing caching strategy: 'generateSW' and 'InjectManifest'.&lt;br&gt;
We can use 'generateSW' when we don't have any configuration and we just want to precache essential static resources. Otherwise it's necessary to use InjectManifest. You can find more details on workbox webpack plugin &lt;a href="https://developers.google.com/web/tools/workbox/modules/workbox-webpack-plugin" rel="noopener noreferrer"&gt;here&lt;/a&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%2Fuqcukqlhw6dj3y0g5dm0.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%2Fuqcukqlhw6dj3y0g5dm0.png" alt="How does PWA plugin add precaching to your project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Improve Reach offline exprience of your users&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you prefer to skip the details and go directly to the code, visit my repository &lt;a href="https://github.com/pegahsafaie/vue-cli-PWA-plugin" rel="noopener noreferrer"&gt;here&lt;/a&gt; on github.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We have seen how does Vue CLI PWA plugin applies precaching to our webpage. Now Let's  improve the project by adding an API request to load some data. It gets an ip address and returns a country name.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fctcan450s0zpsc8gvy6j.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%2Fctcan450s0zpsc8gvy6j.jpg" alt="By pressing "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;How can I cache the response from my API? Can I rely on the default configuration of the PWA Vue CLI plugin?&lt;br&gt;
Unfortunately no! This time we have to add the caching strategy ourselves.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;How should we start?&lt;br&gt;
First we need to determine our caching strategy. Google offers a list of caching strategies for a quick start called an &lt;a href="https://web.dev/offline-cookbook/" rel="noopener noreferrer"&gt;offline cookbook&lt;/a&gt;. &lt;br&gt;
I also made a simple matrix out of these strategies, so it's easier for me to choose what I want.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Updates Frequency / Fallback Support&lt;/th&gt;
&lt;th&gt;High&lt;/th&gt;
&lt;th&gt;Low&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;True&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Network First/Stale While Revalidate&lt;/td&gt;
&lt;td&gt;Cache First&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;False&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Network Only&lt;/td&gt;
&lt;td&gt;Cache Only&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Does my API response update often? No! We always get the same country for the       same ip.&lt;br&gt;
Does my API need a fallback? Sure. I don't want to enter a risk and not show anything when my cache is empty for the first time.&lt;/p&gt;

&lt;p&gt;So i take &lt;a href="https://web.dev/offline-cookbook/#cache-falling-back-to-network" rel="noopener noreferrer"&gt;Cache First strategy&lt;/a&gt; which says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We look in the cache first. If the resource is there we use it. If not, we get it from the network and also update the cache using the response of the network.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I know my strategy. Where should I put it? &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Vue CLI PWA plugin configuration is handled via the &lt;code&gt;pwa&lt;/code&gt; property of either the &lt;code&gt;vue.config.js&lt;/code&gt; file, or the &lt;code&gt;"vue"&lt;/code&gt; field in &lt;code&gt;package.json&lt;/code&gt;. You can find more details &lt;a href="https://cli.vuejs.org/core-plugins/pwa.html#example-configuration" rel="noopener noreferrer"&gt;here&lt;/a&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the previous section, we learned that the Workbox webpack plugin includes two caching modules: 'generateSW' and 'InjectManifest'. To customize our caching strategy, we call 'InjectManifest'. The InjectManifest Module requires a js file which contains our extra scripts or logic.&lt;br&gt;
&lt;/p&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Inside vue.config.js&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...other vue-cli plugin options...&lt;/span&gt;
  &lt;span class="na"&gt;pwa&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;workboxPluginMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;InjectManifest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;workboxOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// swSrc is required in InjectManifest mode.&lt;/span&gt;
      &lt;span class="na"&gt;swSrc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/service-worker.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Let's put our new strategy in the src/service-worker.js file.
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;span class="c1"&gt;// define a prefix for your cache names. It is recommended to use your project name&lt;/span&gt;
&lt;span class="nx"&gt;workbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setCacheNameDetails&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;simple-vue-project&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Start of Precaching##########################&lt;/span&gt;
&lt;span class="c1"&gt;// __precacheManifest is the list of resources you want to precache. This list will be generated and imported automatically by workbox during build time&lt;/span&gt;
&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__precacheManifest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[].&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__precacheManifest&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;span class="nx"&gt;workbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;precaching&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;precacheAndRoute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__precacheManifest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;
&lt;span class="c1"&gt;// End of Precaching############################&lt;/span&gt;

&lt;span class="c1"&gt;// Start of CachFirst Strategy##################&lt;/span&gt;
&lt;span class="c1"&gt;// all the api request which matchs the following pattern will use CacheFirst strategy for caching&lt;/span&gt;
&lt;span class="nx"&gt;workbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;routing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerRoute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="sr"&gt;/https:&lt;/span&gt;&lt;span class="se"&gt;\/\/&lt;/span&gt;&lt;span class="sr"&gt;get&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;geojs&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;io&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;v1&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;ip&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;country&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;json/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt;  &lt;span class="nx"&gt;workbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;strategies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CacheFirst&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// End of CachFirst Strategy####################&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you might have noticed, once you switch from 'GenerateSW' mode to 'InvokeManifest' mode, there is no default precaching and everything has to be added by hand to the script.&lt;/p&gt;

&lt;p&gt;You might be wondering where the workbox came from. There was no import! Workbox injects the whole library from the official CDN during the build process. Not ideal but quick and easy for our tutorial. More information &lt;a href="https://developers.google.com/web/tools/workbox/modules/workbox-sw" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test our imporvements&lt;/strong&gt;&lt;br&gt;
Let's check the application and network tabs to make sure our code works. As we mentioned earlier: the app must be built and deployed to your localhost.&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%2F8f5tfjlj5lgiw9l7hqn9.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%2F8f5tfjlj5lgiw9l7hqn9.jpg" alt="Alt Text"&gt;&lt;/a&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%2Fib9w4pyaxxeo99ste5zj.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%2Fib9w4pyaxxeo99ste5zj.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Once you make an API call, The response data will be cached and you can see it in your cache list. Now if you switch to offline mode and call the API again, you will receive the response data from the cache.&lt;/p&gt;

&lt;p&gt;Congratulations! Your caching strategy has been customized! Please leave me a comment if you have further questions regarding the customization of your caching strategies😊.&lt;/p&gt;

</description>
      <category>vue</category>
      <category>pwa</category>
      <category>cli</category>
      <category>cache</category>
    </item>
  </channel>
</rss>
