<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Uploadcare</title>
    <description>The latest articles on Forem by Uploadcare (@uploadcare).</description>
    <link>https://forem.com/uploadcare</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%2F572354%2F534e27ec-1ab3-4f1d-a5e7-a33d9585135d.png</url>
      <title>Forem: Uploadcare</title>
      <link>https://forem.com/uploadcare</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/uploadcare"/>
    <language>en</language>
    <item>
      <title>Vitest: Blazing fast unit test framework</title>
      <dc:creator>Uploadcare</dc:creator>
      <pubDate>Tue, 31 Jan 2023 14:37:06 +0000</pubDate>
      <link>https://forem.com/uploadcare/vitest-blazing-fast-unit-test-framework-4lco</link>
      <guid>https://forem.com/uploadcare/vitest-blazing-fast-unit-test-framework-4lco</guid>
      <description>&lt;p&gt;If you have heard of Vite, then you have probably heard of Vitest, the fast unit test framework built from it. In this article, let’s explore what Vitest is, how to use it and why it can be the next test framework for your apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Vitest
&lt;/h2&gt;

&lt;p&gt;Before we get into Vitest, let’s note that Vite is a build tool that allows for faster server starts and updates thanks to its native ESM-based method to serve code on demand:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--shzHyTtH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p0tv5czqphiq8x6sonu8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--shzHyTtH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p0tv5czqphiq8x6sonu8.png" alt="Vite dev server structure: server gets HTTP request, finds a suitable route, which leads to the exact module that should be processed and served; all of that due to dynamic imports" width="880" height="551"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you want to get more, feel free to read my &lt;a href="https://lo-victoria.com/introduction-to-vite-the-next-generation-frontend-tooling"&gt;Introduction to Vite&lt;/a&gt; article.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So Vitest is the unit testing framework built on top of Vite and is an excellent unit test framework with many modern features such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Component testing for Vue, React, Svelte, Lit and more.&lt;/li&gt;
&lt;li&gt;Out-of-the-box TypeScript and JSX support.&lt;/li&gt;
&lt;li&gt;ESM first, top level &lt;code&gt;await&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Multithreading workers.&lt;/li&gt;
&lt;li&gt;Filtering, timeouts, concurrent for suite and tests.&lt;/li&gt;
&lt;li&gt;Jest-compatible snapshot testing.&lt;/li&gt;
&lt;li&gt;Chai built-in for assertions + Jest &lt;code&gt;expect&lt;/code&gt; compatible APIs.&lt;/li&gt;
&lt;li&gt;Designed with a Jest compatible API.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s get started with a simple example on how to use Vitest in a Vite-powered project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example usage: writing unit tests in Vitest
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1. Create a Vite project
&lt;/h3&gt;

&lt;p&gt;It’s simple, just type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm create vite &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: Vite requires Node.js version 14.18+ or 16+.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This will start the process to create a Vite project. You can name your project and choose a template appropriately. For this example, I will be choosing the Vanilla template and TypeScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm create vite .
✔ Package name: … vitest
✔ Select a framework: › Vanilla
✔ Select a variant: › TypeScript

Scaffolding project in /tmp/vitest...

Done. Now run:

  npm install
  npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you see, after the project is created, you can install the necessary dependencies by running:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Now, you should have the following project structure:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aNPIVb-n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qohij1bjys3vbe5ng6u6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aNPIVb-n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qohij1bjys3vbe5ng6u6.png" alt="node_modules, public &amp;amp; src directories, plus some files: .gitignore, index.html, package-lock.json, package.json and tsconfig.json" width="389" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, to install Vitest, run:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h4&gt;
  
  
  Alternative for non-Vite powered projects
&lt;/h4&gt;

&lt;p&gt;It is just as easy to setup Vitest in a non-Vite powered projects.&lt;br&gt;
Say we have a CRA project and want to use Vitest for testing.&lt;/p&gt;

&lt;p&gt;All we need to do is to run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; vitest @vitejs/plugin-react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then add a &lt;em&gt;vite.config.js&lt;/em&gt; in the root folder of the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// &amp;lt;reference types="vitest" /&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vitest/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;react&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@vitejs/plugin-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;react&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
  &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;open&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;outDir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;build&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;sourcemap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;commonjsOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;optimizeDeps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jsdom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;setupFiles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testing-library/jest-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;mockReset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2. Write some simple tests
&lt;/h3&gt;

&lt;p&gt;Now that our project is set up, let us write some simple tests.&lt;/p&gt;

&lt;p&gt;Vitest has been designed based on Jest, so it shares a lot of similarities. One of them is that it can automatically detect your test files as long as you name it in any of the 3 following formats:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A &lt;em&gt;.js&lt;/em&gt; file in a folder named &lt;em&gt;__tests__.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;A file with a name like &lt;em&gt;[name].spec.js.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;A file with a name like &lt;em&gt;[name].test.js.&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So let’s create a new folder in our example project called &lt;em&gt;tests&lt;/em&gt; and add a &lt;em&gt;basic.test.js&lt;/em&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tests/
    |- basic.test.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this file, let’s add some simple tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vitest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Math.sqrt() test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SQRT4&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SQRT144&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;144&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SQRT2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sqrt&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="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SQRT2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have worked with other testing libraries such as Jest, Mocha or Jasmine, you should be familiar with the BDD (Behavior Driven Development) pattern. It &lt;strong&gt;describes&lt;/strong&gt; a function, explains what &lt;strong&gt;it&lt;/strong&gt; does and uses test case(s) to &lt;strong&gt;assert&lt;/strong&gt; that it works as intended.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3. Run tests
&lt;/h3&gt;

&lt;p&gt;To run the tests, the command is:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Or you can configure your &lt;em&gt;package.json&lt;/em&gt; to run the command with &lt;code&gt;npm test&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vitest"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;More Vitest CLI commands can be found at the &lt;a href="https://vitest.dev/guide/cli.html"&gt;official documentation&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;By default, the tests run in watch mode so if you make any file changes, they will re-run immediately. If the tests are successful, you should see the terminal outputting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npx vitest

 DEV  v0.27.2 /tmp/vitest

 ✓ tests/basic.test.js (1)

 Test Files  1 passed (1)
      Tests  3 passed (3)
   Start at  15:05:07
   Duration  933ms (transform 379ms, setup 0ms, collect 13ms, tests 2ms)


 PASS  Waiting for file changes...
       press h to show help, press q to quit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Vitest VS Code extension
&lt;/h2&gt;

&lt;p&gt;To speed up testing and make debugging easier,&lt;br&gt;
there is a &lt;a href="https://marketplace.visualstudio.com/items?itemName=ZixuanChen.vitest-explorer"&gt;VS Code extension for Vitest&lt;/a&gt; available in the Marketplace.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4Kn_b5Sj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/akmaf7jx99fvfbnvsaov.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4Kn_b5Sj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/akmaf7jx99fvfbnvsaov.png" alt="VS Code extension showing the list of tests and allowing to pick which one to start" width="880" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This extension can help to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;filter tests by status,&lt;/li&gt;
&lt;li&gt;debug easier,&lt;/li&gt;
&lt;li&gt;inspect console output,&lt;/li&gt;
&lt;li&gt;rerun tests faster.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Vitest vs Other test frameworks
&lt;/h2&gt;

&lt;p&gt;Vitest is often compared to Jest, another popular test framework.&lt;br&gt;
It is because it is built on top of Jest, making it a more modern and improved version. Also, it offers compatibility with most of the Jest API and ecosystem libraries, making it simple to migrate by following their official guide here.&lt;/p&gt;

&lt;p&gt;Just like other widely used test frameworks such as Mocha and Jasmine, Vitest follows a simple &lt;strong&gt;describe-it-assert&lt;/strong&gt; or &lt;strong&gt;describe-it-expect&lt;/strong&gt; pattern. The advantage of using Vitest over them is that it is fast to set up and does not require installing a separate assertion library.&lt;/p&gt;

&lt;p&gt;The most convenient advantage of using Vitest is that it requires minimal configuration and can be used with any bundler. You can define the configuration for your dev, build and test environments as a single pipeline under &lt;em&gt;vite.config.js.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A simple example would be setting up a Jest and Babel environment for a React app. Often, you would need to install additional packages besides the ones that come with CRA:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;babel-jest,&lt;/li&gt;
&lt;li&gt;
&lt;a class="mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;/core,&lt;/li&gt;
&lt;li&gt;
&lt;a class="mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;/preset-env,&lt;/li&gt;
&lt;li&gt;
&lt;a class="mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;/preset-react,&lt;/li&gt;
&lt;li&gt;
&lt;a class="mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;/preset-typescript,&lt;/li&gt;
&lt;li&gt;@types/jest.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After that, you would need a &lt;em&gt;jest.config.js&lt;/em&gt; and a &lt;em&gt;babel.config.js&lt;/em&gt; to complete setting up the configuration.&lt;/p&gt;

&lt;p&gt;With Vitest, you don’t have to install those extra dependencies. All you need is a &lt;em&gt;vite.config.js&lt;/em&gt; or &lt;em&gt;vitest.config.js&lt;/em&gt; file. Even for non-Vite projects, it is a single file to configure. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vitest/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jsdom&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Learn more about configuration in the &lt;a href="https://vitest.dev/config/"&gt;official documentation&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here is a summarized comparison of different popular test frameworks with Vitest:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;thead&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;/td&gt;
    &lt;th&gt;Pros&lt;/th&gt;
    &lt;th&gt;Cons&lt;/th&gt;
  &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
  &lt;tr&gt;
    &lt;th&gt;Jest&lt;/th&gt;
    &lt;td&gt;
      &lt;ul&gt;
        &lt;li&gt;Compatible with most frameworks like React, Vue, and Babel-based projects.&lt;/li&gt;
        &lt;li&gt;Performance is good.&lt;/li&gt;
        &lt;li&gt;Supports asynchronous code and other wide range of tests.&lt;/li&gt;
        &lt;li&gt;Extended API, can be optionally included when needed.&lt;/li&gt;
        &lt;li&gt;Auto mock any libraries imported for easy testing.&lt;/li&gt;
        &lt;li&gt;Highly active community support.&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/td&gt;
    &lt;td&gt;
      &lt;ul&gt;
        &lt;li&gt;Auto mocking can slow down performance.&lt;/li&gt;
        &lt;li&gt;When used with third-party libraries or tools, it may not be supported or difficult to configure.&lt;/li&gt;
        &lt;li&gt;Can require a lot of dependencies to set up (i.e. Babel projects).&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;th&gt;Mocha&lt;/th&gt;
    &lt;td&gt;
      &lt;ul&gt;
        &lt;li&gt;Simple, lightweight and easy to get into.&lt;/li&gt;
        &lt;li&gt;Flexible to configure and include different libraries with.&lt;/li&gt;
        &lt;li&gt;Active community support.&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/td&gt;
    &lt;td&gt;
      &lt;ul&gt;
        &lt;li&gt;Does not come with a lot of features and need to install other libraries separately.&lt;/li&gt;
        &lt;li&gt;Can be hard to configure as different dependencies has different requirements.&lt;/li&gt;
        &lt;li&gt;Can be complex to include auto mocking or snapshot testing.&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;th&gt;Jasmine&lt;/th&gt;
    &lt;td&gt;
      &lt;ul&gt;
        &lt;li&gt;Very flexible and is compatible with most frameworks and libraries.&lt;/li&gt;
        &lt;li&gt;Built-in assertion library, so it doesn’t require additional libraries.&lt;/li&gt;
        &lt;li&gt;Easy to read and clean syntax.&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/td&gt;
    &lt;td&gt;
      &lt;ul&gt;
        &lt;li&gt;Difficult to test asynchronous code.&lt;/li&gt;
        &lt;li&gt;Not as widely used as newer test frameworks.&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;th&gt;Vitest&lt;/th&gt;
    &lt;td&gt;
      &lt;ul&gt;
        &lt;li&gt;Native ESM and out-of-box TypeScript support.&lt;/li&gt;
        &lt;li&gt;Multithreaded and lightweight.&lt;/li&gt;
        &lt;li&gt;Minimal configuration and setup needed.&lt;/li&gt;
        &lt;li&gt;Build upon Jest API, includes all Jest testing features.&lt;/li&gt;
        &lt;li&gt;Performance is fast, live reloads are faster than Jest.&lt;/li&gt;
        &lt;li&gt;Highly compatible with Vite projects.&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/td&gt;
    &lt;td&gt;
      &lt;ul&gt;
        &lt;li&gt;Still in early phase, may not have active community support.&lt;/li&gt;
        &lt;li&gt;Does not use a global module like Jest and isolates each test to run, may affect performance when scaling.&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/td&gt;
  &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  More features. Test coverage report
&lt;/h2&gt;

&lt;p&gt;Let’s see a simple example how we can output a test coverage report. First, let’s create a simple counter function in &lt;em&gt;counter.js:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;setCounter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, let’s create a test for this function in the &lt;em&gt;counter.test.js:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vitest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;setCounter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../src/counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;setCounter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;returns 1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;setCounter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if we run &lt;code&gt;vitest run --coverage&lt;/code&gt;, we can see how much of our code has been tested:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ vitest run --coverage

 RUN  v0.27.2 /tmp/vitest
      Coverage enabled with c8

 ✓ tests/counter.test.js (1)

 Test Files  1 passed (1)
      Tests  1 passed (1)
   Start at  15:19:08
   Duration  2.12s (transform 390ms, setup 0ms, collect 40ms, tests 2ms)

 % Coverage report from c8
------------|---------|----------|---------|---------|-------------------
File        | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
------------|---------|----------|---------|---------|-------------------
All files   |     100 |      100 |     100 |     100 |
 counter.ts |     100 |      100 |     100 |     100 |
------------|---------|----------|---------|---------|-------------------
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s say we add a new function in our &lt;em&gt;counter.js&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// added another function&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;setupCounter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;setCounter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`count is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we run &lt;code&gt;vitest run --coverage&lt;/code&gt;, we can see that not all our code has been tested:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ vitest run --coverage

 RUN  v0.27.2 /tmp/vitest
      Coverage enabled with c8

 ✓ tests/counter.test.js (1)

 Test Files  1 passed (1)
      Tests  1 passed (1)
   Start at  15:31:52
   Duration  2.03s (transform 480ms, setup 0ms, collect 40ms, tests 2ms)

 % Coverage report from c8
------------|---------|----------|---------|---------|-------------------
File        | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
------------|---------|----------|---------|---------|-------------------
All files   |   54.54 |      100 |      50 |   54.54 |
 counter.ts |   54.54 |      100 |      50 |   54.54 | 7-11
------------|---------|----------|---------|---------|-------------------
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This report ensures that most of your project’s code is tested.&lt;/p&gt;

&lt;p&gt;By default, Vitest uses the c8 package to run coverage reports. You may install it manually with the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-D&lt;/span&gt; @vitest/coverage-c8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or install it when prompted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ vitest run --coverage
 MISSING DEP  Can not find dependency '@vitest/coverage-c8'

 ✔ Do you want to install @vitest/coverage-c8? …
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Even more features. Component testing
&lt;/h2&gt;

&lt;p&gt;Another common testing we can do with Vitest is component testing, which verifies the functionality of individual components.&lt;/p&gt;

&lt;p&gt;Let’s add an &lt;em&gt;App.test.jsx&lt;/em&gt; to a React App. For this example, we’re using a non-Vite project (i.e. basic Create React App template) to show that Vitest works just as fine.&lt;/p&gt;

&lt;p&gt;In this test, we want to test only the App component and here’s what our &lt;em&gt;App.test.jsx&lt;/em&gt; will look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testing-library/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vitest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;App Component Test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;it&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;renders without crashing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toBeInTheDocument&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;renders learn react link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;linkElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/learn react/i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;linkElement&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toBeInTheDocument&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we run the tests with &lt;code&gt;npm test&lt;/code&gt; or &lt;code&gt;npx vitest&lt;/code&gt;. The 2 tests should pass successfully, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npx vitest

 DEV  v0.27.2 /tmp/vitest

 ✓ tests/App.test.jsx (1)

 Test Files  1 passed (1)
      Tests  2 passed (2)
   Start at  16:12:12
   Duration  1.94s (transform 685ms, setup 126ms, collect 356ms, tests 37ms)


 PASS  Waiting for file changes...
       press h to show help, press q to quit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;In this article, we learned about Vitest, a fast and modern unit testing framework powered by Vite. Thanks for reading, I hope it has been a helpful article in getting you started with Vitest. Please refer to the References section below if you would like to read more about Vitest and Vite. Cheers!&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://vitest.dev/guide/"&gt;Getting started with Vitest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vitest.dev/guide/coverage.html"&gt;Test coverage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vitest.dev/guide/comparisons.html"&gt;Comparisons with other test runners&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vitejs.dev/"&gt;About Vite&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Originally published by Victoria Lo in &lt;a href="https://uploadcare.com/blog/vitest-unit-test-framework/"&gt;Uploadcare Blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>testing</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>What is NaN in JavaScript?</title>
      <dc:creator>Uploadcare</dc:creator>
      <pubDate>Wed, 25 Jan 2023 15:56:50 +0000</pubDate>
      <link>https://forem.com/uploadcare/what-is-nan-in-javascript-3i0e</link>
      <guid>https://forem.com/uploadcare/what-is-nan-in-javascript-3i0e</guid>
      <description>&lt;p&gt;This article is a part of the ReturnTrue series. Here we solve &lt;a href="https://alf.nu/ReturnTrue"&gt;ReturnTrue puzzles&lt;/a&gt; and try to explain how we find solutions and why exactly they work.&lt;/p&gt;

&lt;p&gt;The goal is not to show the answers but to dive deep into the elaborate internals of JavaScript and browsers. Yet, we recommend you try to find solutions yourself. It would be more interesting this way, be sure.&lt;/p&gt;

&lt;p&gt;Now let’s continue our journey and move to the 2nd task and the main topic of this article — NaN.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reflexive
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;reflexive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are an experienced developer, you know the answer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;reflexive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But there is something to discuss.&lt;/p&gt;

&lt;h2&gt;
  
  
  First, why is it “reflexive”?
&lt;/h2&gt;

&lt;p&gt;In a nutshell, a binary relation across a set is &lt;a href="https://en.wikipedia.org/wiki/Reflexive_relation"&gt;reflexive&lt;/a&gt; if each element of the set is related to itself.&lt;/p&gt;

&lt;p&gt;Math definitions from Wikipedia, brrr. Let’s explain it another way.&lt;/p&gt;

&lt;p&gt;Imagine a set of natural numbers. You can take any number and check whether it equals itself or not:&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="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If this check returns &lt;code&gt;true&lt;/code&gt; for all the natural numbers, then equality is “reflexive” for them.&lt;/p&gt;

&lt;p&gt;The same goes for inequality. Inequality is “anti-reflexive” because it’s &lt;code&gt;false&lt;/code&gt; for all the natural numbers:&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="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But NaN is not equal to itself. It means that for NaN equality is anti-reflexive, while inequality is reflexive. Hence the name.&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="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt;
&lt;span class="kc"&gt;false&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt;
&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Second, how to get NaN in JavaScript?
&lt;/h2&gt;

&lt;p&gt;If we try to make a number from a non-numeric string, JavaScript will not throw an exception. Instead, it will return NaN. It is, well, understandable. But JavaScript is one of the few languages that returns NaN in such a common operation.&lt;/p&gt;

&lt;p&gt;E.g. Python throws an exception:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python nan.py
Traceback &lt;span class="o"&gt;(&lt;/span&gt;most recent call last&lt;span class="o"&gt;)&lt;/span&gt;:
  File &lt;span class="s2"&gt;"./nan.py"&lt;/span&gt;, line 1, &lt;span class="k"&gt;in&lt;/span&gt; &amp;lt;module&amp;gt;
    int&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"a"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
ValueError: invalid literal &lt;span class="k"&gt;for &lt;/span&gt;int&lt;span class="o"&gt;()&lt;/span&gt; with base 10: &lt;span class="s1"&gt;'a'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PHP returns zero:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?&lt;/span&gt;
&lt;span class="nv"&gt;$str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;php &lt;span class="nt"&gt;-f&lt;/span&gt; nan.php
0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But JavaScript says:&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="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kc"&gt;NaN&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s why every JavaScript newbie knows about NaN. Usually, they do not go further than &lt;em&gt;"NaN is, eh, when a string to number conversion failed".&lt;/em&gt; But we will go deeper.&lt;/p&gt;

&lt;h2&gt;
  
  
  Going deeper
&lt;/h2&gt;

&lt;p&gt;As you know, when &lt;code&gt;parseInt&lt;/code&gt; can not do its job, it returns NaN:&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="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kc"&gt;NaN&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, we have to check the result of such parsing for NaN. There is a global function &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN"&gt;&lt;code&gt;isNaN&lt;/code&gt;&lt;/a&gt;, that is available since the first edition of ECMAScript. This function is suitable for this check, but you should not trust it all the time. &lt;code&gt;isNaN&lt;/code&gt; tries to convert the passed argument to a number before the very check. That’s why &lt;code&gt;isNaN&lt;/code&gt; returns &lt;code&gt;true&lt;/code&gt; for any value that it can’t convert to a number:&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="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;isNaN&lt;/span&gt;&lt;span class="p"&gt;({})&lt;/span&gt;
&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this in mind, the standard authors should have named &lt;code&gt;isNaN&lt;/code&gt; — &lt;code&gt;canNotBeConvertedToNumber&lt;/code&gt;. To fix this issue, they introduced &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN"&gt;&lt;code&gt;Number.isNaN&lt;/code&gt;&lt;/a&gt; in ES6, which works as expected:&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="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;isNaN&lt;/span&gt;&lt;span class="p"&gt;({})&lt;/span&gt;
&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unclear browser API is not the only problem in JavaScript related to NaN. As you also may know, NaN as an operand transforms any arithmetic operation result into NaN:&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="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt;
&lt;span class="kc"&gt;NaN&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Plus, NaN does not equal anything, even itself:&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="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt;
&lt;span class="kc"&gt;false&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt;
&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Such behavior is so unique that the spec suggests checking NaN using a strict inequality operation. Like, duck testing:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;A reliable way for ECMAScript code to test if a value &lt;code&gt;X&lt;/code&gt; is a &lt;code&gt;NaN&lt;/code&gt; is an expression of the form &lt;code&gt;X !== X&lt;/code&gt;. The result will be &lt;code&gt;true&lt;/code&gt; if and only if &lt;code&gt;X&lt;/code&gt; is a &lt;code&gt;NaN&lt;/code&gt;.&lt;/p&gt;
  &lt;p&gt;— &lt;a href="https://www.ecma-international.org/ecma-262/11.0/index.html#sec-isnan-number"&gt;18.2.3 isNaN&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It’s important to note here that this situation is not the same as we have with objects in JavaScript:&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="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But in this case we’re comparing &lt;em&gt;two different objects,&lt;/em&gt; while with NaN we’re comparing the same value.&lt;br&gt;
To make it clear, consider these examples:&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="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;
&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt;
&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Anyway, aside from those described above, there are plenty of other ways to get NaN in JavaScript. Most of them are not related to arithmetic operations at all. E.g., you can try to get a code of the character of the string outside of the length of this string:&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="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;charCodeAt&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="kc"&gt;NaN&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or parse an invalid date string:&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="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kc"&gt;NaN&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From some perspective, the fact that we get NaN in such cases is okay, but is it? If you can’t get a code of the character of the string, you would like to get an exception signaling the error. But in JavaScript, access to any non-existing element of an array does not lead to an error:&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="o"&gt;&amp;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="kc"&gt;undefined&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({})[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="kc"&gt;undefined&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="kc"&gt;undefined&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s why in our case JavaScript tries to return a “thing”, which is a number and an error at the same time. You know, NaN is a number:&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="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt;
&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;Shameless plug you may want to click on:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://uploadcare.com/docs/"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GnJyMH8l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sjlc5at8b4a90hr7h8a1.png" alt="Look at this" width="880" height="284"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Going even deeper
&lt;/h2&gt;

&lt;p&gt;The NaN weirdness in JavaScript does not end here.&lt;/p&gt;

&lt;p&gt;If we try to get the NaN-th character of the non-empty string, we’ll get it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;charAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works this way because sometimes JS converts NaN to zero behind the scenes. Surprise!&lt;/p&gt;

&lt;p&gt;There are lots of different type conversions described in the spec. One of them is &lt;code&gt;ToInteger&lt;/code&gt;. JavaScript uses it when a standard function expects an integer argument. Before the use of the passed argument, JavaScript applies &lt;code&gt;ToInteger&lt;/code&gt; to the value of that argument. If the value is NaN, then &lt;code&gt;ToInteger&lt;/code&gt; replaces it with zero:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;2. If number is &lt;code&gt;NaN&lt;/code&gt;, &lt;code&gt;+0&lt;/code&gt;, or &lt;code&gt;-0&lt;/code&gt;, return &lt;code&gt;+0&lt;/code&gt;.&lt;/p&gt;
  &lt;p&gt;— &lt;cite&gt;&lt;a href="https://www.ecma-international.org/ecma-262/11.0/index.html#sec-tointeger"&gt;7.1.5 ToInteger&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Aside from that, there are more curious cases with NaN. Check this out:&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="o"&gt;&amp;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="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="o"&gt;&amp;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="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;NaN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;indexOf&lt;/code&gt; can’t find NaN, while &lt;code&gt;includes&lt;/code&gt; can. Why? Because &lt;code&gt;indexOf&lt;/code&gt; uses strict equality checks during the search. NaN does not equal itself, so &lt;code&gt;indexOf&lt;/code&gt; can’t find it.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;includes&lt;/code&gt; search is a bit more complicated. It has an explicit check for NaN for the argument and array values.&lt;/p&gt;

&lt;p&gt;Another example is exponentiation which goes nuts when we pass NaN. Yeah, we know that “NaN turns any arithmetic operation into NaN” but for the sake of God, what is going on here?&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="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;NaN&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s a tricky question. Exponentiation in JavaScript does not care what exactly you are trying to raise to the power 0. The result will always be the same:&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="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;wtf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;orly&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Honestly, the exponentiation algorithm is not that simple at all:&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="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mf"&gt;1.2&lt;/span&gt;
&lt;span class="kc"&gt;NaN&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we get NaN not because of JavaScript weirdness, but that’s the story for the next time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wait, but what is NaN, once again?
&lt;/h2&gt;

&lt;p&gt;Oh, glad you asked!&lt;/p&gt;

&lt;p&gt;JavaScript implementations are trying to be ECMAScript compliant, right? Let’s check what the spec says about NaN:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Number value that is a IEEE 754 “Not-a-Number” value.&lt;/p&gt;
  &lt;p&gt;— &lt;cite&gt;&lt;a href="https://www.ecma-international.org/ecma-262/11.0/index.html#sec-terms-and-definitions-nan"&gt;4.3.24 NaN&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;sigh&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Alright, what is that IEEE 754 thing?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Institute_of_Electrical_and_Electronics_Engineers"&gt;IEEE&lt;/a&gt; stands for “Institute of Electrical and Electronics Engineers”. It is a professional association that develops engineering standards. In particular, they create standards for telecommunications.&lt;/p&gt;

&lt;p&gt;There are IEEE standards for the many things we use daily. E.g. &lt;a href="https://en.wikipedia.org/wiki/POSIX"&gt;IEEE 1003&lt;/a&gt; is POSIX, while &lt;a href="https://en.wikipedia.org/wiki/IEEE_802"&gt;IEEE 802&lt;/a&gt; is a set of standards describing different networks. In particular, &lt;a href="https://en.wikipedia.org/wiki/IEEE_802.11"&gt;802.11&lt;/a&gt; describes wireless communications, in other words — Wi-Fi. Hence the “versions” of Wi-Fi: 802.11a, 802.11b, and so on. All of them are different versions of that standard.&lt;/p&gt;

&lt;p&gt;So, &lt;a href="https://en.wikipedia.org/wiki/IEEE_754"&gt;IEEE 754&lt;/a&gt; is a standard for floating-point arithmetic. It describes the implementation of floating point numbers and operations for them what those numbers are we will see in the next articles&lt;/p&gt;

&lt;p&gt;Among other things, the standard defines NaN as a special numeric value. Computers should return NaN when they can’t find the operation result. For example, when it’s impossible to compute or the operation itself is invalid.&lt;/p&gt;

&lt;p&gt;There are lots of examples of such operations. There are the ones the standard describes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;0 by 0 or ∞ by ∞ division;&lt;/li&gt;
&lt;li&gt;0 by ∞ multiplication;&lt;/li&gt;
&lt;li&gt;getting a reminder of ∞ by 0 division;&lt;/li&gt;
&lt;li&gt;subtraction of infinities of the same sign;&lt;/li&gt;
&lt;li&gt;and so on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is NaN in most programming languages because they follow the standard. But not all the operations listed above return NaN in those languages. Some may throw exceptions if the language developers have decided so. Otherwise, NaN is usually used.&lt;/p&gt;

&lt;p&gt;For instance, you can not divide by zero in Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python zero.py
Traceback &lt;span class="o"&gt;(&lt;/span&gt;most recent call last&lt;span class="o"&gt;)&lt;/span&gt;:
  File &lt;span class="s2"&gt;"./zero.py"&lt;/span&gt;, line 1, &lt;span class="k"&gt;in&lt;/span&gt; &amp;lt;odule&amp;gt;
ZeroDivisionError: division by zero
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But you can get NaN by trying to add +∞ to −∞:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'inf'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'-inf'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python inf.py
nan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go will do the same, while in PHP you may get NaN by trying to get an arccosine of the value out of [−1; 1]:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nb"&gt;acos&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="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;php &lt;span class="nt"&gt;-f&lt;/span&gt; acos.php
NaN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same is true for C.&lt;/p&gt;

&lt;p&gt;As you see, programming languages work with NaN in varied ways. They may not even use NaN in arithmetic. They may throw exceptions in “critical” cases and return defaults in the others.&lt;/p&gt;

&lt;p&gt;But some languages use NaN for all the awkward cases. JavaScript is one of those languages.&lt;/p&gt;

&lt;p&gt;NaN and floating-point arithmetic are extensive and intriguing topics. But that’s all for today, folks!&lt;/p&gt;

&lt;p&gt;If you wish to continue the journey, here is the cliffhanger. There is not one NaN for “all the weirdness”. IEEE 754 defines two of them: quiet NaN and signaling NaN. Happy research! &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published by Igor Adamenko in &lt;a href="https://uploadcare.com/blog/what-is-nan/"&gt;Uploadcare Blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>TCP &amp; UDP, or the two pillars of the Internet</title>
      <dc:creator>Uploadcare</dc:creator>
      <pubDate>Sun, 22 Jan 2023 16:30:08 +0000</pubDate>
      <link>https://forem.com/uploadcare/tcp-udp-or-the-two-pillars-of-the-internet-23ch</link>
      <guid>https://forem.com/uploadcare/tcp-udp-or-the-two-pillars-of-the-internet-23ch</guid>
      <description>&lt;p&gt;As a company who offers a &lt;a href="https://uploadcare.com/cdn/" rel="noopener noreferrer"&gt;CDN service&lt;/a&gt; we know a lot about this technology. In this series of articles we’re trying to describe how a CDN works and what are the things that make the existence of CDN possible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/uploadcare/basics-of-the-internet-mdh"&gt;In the previous article&lt;/a&gt; we discussed the structure of the Internet,&lt;br&gt;
the differences between mediums, and the problems that users encounter trying to connect to servers far away from them. Now it’s time to go a few levels up to see what is “the language” computers use to communicate with each other.&lt;/p&gt;
&lt;h2&gt;
  
  
  The plan
&lt;/h2&gt;

&lt;p&gt;There is no way we can even briefly discuss everything that relates to the Internet. Thus, in this and the following articles we are going to look at the exact subset of the technologies — the part laying between physical connection and applications.&lt;/p&gt;

&lt;p&gt;We’re not going to discuss how computers use electricity to represent and transfer data. This topic is fascinating, but it is too low-level for us.&lt;/p&gt;

&lt;p&gt;At the same time we won’t discuss in detail how your browser loads pages: no HTTP requests, no compression, no programming languages evaluation, and no rendering.&lt;/p&gt;

&lt;p&gt;What we are going to discuss is how the data from your computer finds its way to another computer.&lt;/p&gt;
&lt;h2&gt;
  
  
  Switching
&lt;/h2&gt;

&lt;p&gt;If you’re old enough, you might remember the &lt;a href="https://en.wikipedia.org/wiki/Landline" rel="noopener noreferrer"&gt;landlines&lt;/a&gt; we had back in the days at home. Or maybe you still have one! If so, you probably know that a hundred years ago they worked in a semi-manual mode.&lt;/p&gt;

&lt;p&gt;First, you had to ask a switchboard operator (who was a real human) to connect you with your friend from another city. The operator said “OK,” hung up, and then later they called you back with your friend “on line.”&lt;/p&gt;

&lt;p&gt;What you may not know is the procedure this operator had to do for you. They switched cables from one port to another to create the connection:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fensb9c0bejurcznb0crh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fensb9c0bejurcznb0crh.jpg" alt="Around 20 switchboard operators working with a huge old telecommunication machine" width="800" height="655"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This operation is called &lt;em&gt;circuit switching.&lt;/em&gt; Circuit switching is a method of establishing connection between two nodes of a network, when they have a dedicated channel to communicate through. It means that when you dial a friend, there is someone or something that literally builds up a cable path from you to your friend.&lt;/p&gt;

&lt;p&gt;As you might guess, this type of commutation does not suit the Internet well, because we connect all the time to servers all over the world. Implementing physical cable switching for this purpose would be too crazy. It would be too expensive to create and even more expensive to maintain.&lt;/p&gt;

&lt;p&gt;Instead, the Internet is built upon &lt;em&gt;packet switching&lt;/em&gt;. In this type of communication there is no physical cable switching. When we send a message from our computer to our friend’s computer, it goes through different networks, each of those transferring the message to the path that it thinks would be the best.&lt;/p&gt;

&lt;p&gt;This may sound mad, but most of the time there is no “main coordinator” of the Internet who decides where every packet must go. Our computer simply “throws” the packet to the network, and all the devices in this network are trying to decide where this packet should travel. Surprisingly, almost all the time these devices do their job pretty well. All thanks to the protocols!&lt;/p&gt;
&lt;h2&gt;
  
  
  Protocols
&lt;/h2&gt;

&lt;p&gt;A &lt;em&gt;protocol&lt;/em&gt; is a set of rules defined to allow nodes of a network to transmit data properly. You probably know some high-level protocols such as HTTP, SSH, IMAP and DHCP.&lt;/p&gt;

&lt;p&gt;There are tons of protocols in the communication area that are used for different purposes. Due to the huge amount, there are even special models defining “layers of protocols.” We might imagine these layers as a collection of different candy wrappers.&lt;/p&gt;

&lt;p&gt;Let’s say you have ordered a bag of delicious handmade chocolate from a local manufacturer to make a gift for your friend.&lt;/p&gt;

&lt;p&gt;First, a cook wraps a chocolate bar with its own wrapper. Then a packer put the bar into a branded bag. After that somebody from the delivery department uses a piece of wrapping paper to make it look like a gift. Finally, they pass the gift to the postal service.&lt;/p&gt;

&lt;p&gt;When the postal service gets the gift, they put it into a box and write the address of your friend on this box. Then they load a truck with the boxes like yours and go to deliver.&lt;/p&gt;

&lt;p&gt;The process goes vice versa on your friend’s side.&lt;/p&gt;

&lt;p&gt;This wrapping on each step is literally how protocols work on the Internet:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz8tdt2kow3lttapztuof.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz8tdt2kow3lttapztuof.png" alt="A scheme representing the steps described above" width="800" height="938"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  OSI &amp;amp; TCP/IP history
&lt;/h2&gt;

&lt;p&gt;Historically there are two main models that describe protocol layers. One of them is theoretical — the OSI model, another is practical — TCP/IP model.&lt;/p&gt;

&lt;p&gt;There were a lot of possibilities and a lot of problems to solve in the telecommunication area in the 70-80s. There was no Internet as a thing, but there were a bunch of networks created by different companies. Those networks needed a common language to communicate. Therefore many people wanted to create this language. Roughly speaking these people were split into two groups.&lt;/p&gt;

&lt;p&gt;The first group believed that the development of the language should be an open process, with all the criticism discussed and all the issues resolved. This group named the standard they were trying to create as OSI, standing for Open Systems Interconnection.&lt;/p&gt;

&lt;p&gt;Another group chose the different way, they started to develop and test protocols on the network they already had. Thereby, they created TCP — Transmission Control Protocol, and IP — Internet Protocol. Initially, these protocols were the parts of one big protocol, but later they were divided into two to take the maintenance easier.&lt;/p&gt;

&lt;p&gt;This group successfully tested and moved the network they had to this TCP/IP stack. This happened on January 1st, 1983. This is truly &lt;a href="https://blog.google/inside-google/googlers/marking-birth-of-modern-day-internet/" rel="noopener noreferrer"&gt;the day when the Internet was born&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After that TCP/IP started to gain popularity, because it simply worked. Also it was a free of charge model, while authors of OSI wanted to get money for each usage of their standards.&lt;/p&gt;

&lt;p&gt;So, what happened with OSI? &lt;a href="https://spectrum.ieee.org/osi-the-internet-that-wasnt" rel="noopener noreferrer"&gt;The initiative failed&lt;/a&gt;. Due to the idea of “openness”, the people, who made decisions back then, spent a lot of time in discussions and disputes. Some of these people tried to lobby for ideas that were beneficial to large corporations. Others forced everybody to discuss small, not important things.&lt;/p&gt;

&lt;p&gt;Even though the OSI model didn’t find it’s way to the real world, it’s still used as a good theoretical model of protocol layers. But the model that is actually implemented is TCP/IP.&lt;/p&gt;

&lt;p&gt;Here’s how the layers of the models look:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzlyvb06aygelqt279ys4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzlyvb06aygelqt279ys4.png" alt="OSI vs TCP/IP" width="800" height="606"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  TCP/IP
&lt;/h2&gt;

&lt;p&gt;Usually when people discuss OSI and TCP/IP they try to compare these models and match their layers. Even though the pic above looks like a comparison, we are not going to compare the models, because matching of the layers is not so important. Even more, the layering itself is “considered harmful” according to &lt;a href="https://datatracker.ietf.org/doc/html/rfc3439#section-3" rel="noopener noreferrer"&gt;RFC 3439&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The key protocols of TCP/IP are obviously TCP and IP. Everything around them is not so smooth, so even authors of the textbooks about network communication cannot agree with each other about the exact number of layers or their names.&lt;/p&gt;

&lt;p&gt;Is there a Physical Layer below the Network Access Layer? Should we even call Network Access Layer so, or it’s better to call it Link Layer? There are many questions like these. However, all of these questions do not matter, because the main idea of TCP/IP stack is pretty simple.&lt;/p&gt;

&lt;p&gt;Let’s say there are two applications on the network that want to communicate. One of them generates a message. This message may be formatted using a protocol like HTTP, or not, it does not matter. The message is generated on the Application Layer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh291iuahj02rf4xtl6l9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh291iuahj02rf4xtl6l9.png" alt="Message" width="382" height="150"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This message is passed to the Transport Layer, where it’s prepended with a TCP or a UDP header. The header contains information about the ports those applications are using and some other important information which we will describe later. The result of this prepending may be called a &lt;em&gt;datagram&lt;/em&gt; or a &lt;em&gt;segment&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqjh7pf1wykp2bg6ygn9b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqjh7pf1wykp2bg6ygn9b.png" alt="TCP Header + Message" width="800" height="228"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, the segment is passed to the Internet Layer. It’s pretended with an IP header, which contains the addresses of the computers that run the communicating applications. The combination of a segment and an IP header is usually called a &lt;em&gt;packet.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;There is no big difference between datagrams, segments and packets. Most of the time all of them are called “packets.” The terms “datagram” and “segment” are used when it’s important to highlight the type of the protocol handling the entity.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcl86ihi0hasg4l2fb6m2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcl86ihi0hasg4l2fb6m2.png" alt="IP header + TCP header + Message" width="800" height="230"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, the packet is passed to the Link Layer, where it’s encoded and transmitted over the network. There are protocols that also add their own headers to each packet, and the result of this addition is &lt;em&gt;a frame.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Frames usually contain not only the header, but also the footer. E.g. here’s how an Ethernet frame for our message may look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Furf6f7eqxb60ag3syp4g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Furf6f7eqxb60ag3syp4g.png" alt="Ethernet's header and footer are wrapping IP header, TCP header and finally the message" width="800" height="131"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the frame is passed from one intermediate node to another during the communication, these nodes disassemble the frame, check the packet’s header, decide what they should do with the packet, then create a new frame for the packet and pass it to the next node.&lt;/p&gt;

&lt;p&gt;So, when the message is passed through nodes like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7hxttl19eyxio4v4ln7c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7hxttl19eyxio4v4ln7c.png" alt="Message path from left to right: laptop, router, ISP and a destination server" width="800" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The underlying data flow looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqjmx9yjewv40z6kv402d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqjmx9yjewv40z6kv402d.png" alt="At the start and at the end of the packet path all the TCP/IP layers are involved, while the intermediate nodes use only Internet and Network Access layers" width="800" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Alright, now we know that TCP/IP specifies the protocols of the Transport and Internet Layers, but does not really care about the protocols of the Application and Link Layers. Let’s see what’s going on on the Transport layer in detail.&lt;/p&gt;
&lt;h2&gt;
  
  
  TCP &amp;amp; UDP
&lt;/h2&gt;

&lt;p&gt;The Transport Layer of TCP/IP stands on two main protocols: Transmission Control Protocol and User Datagram Protocol. There are other protocols on this layer (e.g. &lt;a href="https://en.wikipedia.org/wiki/QUIC" rel="noopener noreferrer"&gt;QUIC&lt;/a&gt;) but they are not so commonly used yet.&lt;/p&gt;

&lt;p&gt;The protocols of the Transport Layer are used to address the packet from the source port to the destination port. Moreover, the protocols do not know about the differences between nodes on the used network. Everything the protocols know about addressing is the fact that the source application is bound to a port, and the destination application is also bound to a port. The actual “Internet addressing” is done by Internet Protocol which we will describe &lt;a href="https://uploadcare.com/blog/ip/" rel="noopener noreferrer"&gt;in the next article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;UDP is much “lighter” and simpler than TCP, but at the same time UDP is not reliable and does not do much work compared to TCP. To see the difference between these protocols, let’s start with the User Datagram Protocol.&lt;/p&gt;
&lt;h2&gt;
  
  
  User Datagram Protocol
&lt;/h2&gt;

&lt;p&gt;This protocol is used for “connectionless communication,” which means that the connection is not set up prior to the actual sending. One node sends packets to the network addressing them to another node. The sender node does not ensure that the recipient node exists or is ready to receive the packets. The sender node also does not wait for confirmation that the recipient node has got the previous packets.&lt;/p&gt;

&lt;p&gt;The packets handled by UDP are sometimes called &lt;a href="https://en.wikipedia.org/wiki/Datagram" rel="noopener noreferrer"&gt;datagrams&lt;/a&gt;. The term usually describes the packets sent using any connectionless communication.&lt;/p&gt;

&lt;p&gt;UDP header contains 8 bytes of information that includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Source port&lt;/li&gt;
&lt;li&gt;Destination port&lt;/li&gt;
&lt;li&gt;Length&lt;/li&gt;
&lt;li&gt;Checksum&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As simple as it sounds. A typical UDP datagram looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpev10z1605qm6qvcflfp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpev10z1605qm6qvcflfp.png" alt="Source Port, 16 bit; Destination Port, 16 bit; Length, 16 bit; Checksum, 16 bit; Payload, up to 64 Kb" width="800" height="560"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Field test
&lt;/h3&gt;

&lt;p&gt;It’s easy to set up a UDP server on your own. Here is an example written in Node.js right from the &lt;a href="https://nodejs.org/docs/latest-v14.x/api/dgram.html#dgram_udp_datagram_sockets" rel="noopener noreferrer"&gt;official docs&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;dgram&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;dgram&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dgram&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;udp4&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`error:\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rinfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`got a message from &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;rinfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;rinfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;listening&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;address&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`listening &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8082&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s start the server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;node udp.js
server listening 0.0.0.0:8082
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can use &lt;a href="https://en.wikipedia.org/wiki/Netcat" rel="noopener noreferrer"&gt;netcat&lt;/a&gt; to send datagrams from another terminal window:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;nc &lt;span class="nt"&gt;-u&lt;/span&gt; 127.0.0.1 8082
Hello, server!
Do you have a minute to talk about UDP?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our server successfully handles the datagrams we’ve sent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;node udp.js
server listening 0.0.0.0:8082
server got a message from 127.0.0.1:55823: Hello, reader!

server got a message from 127.0.0.1:55823: Do you have a minute to talk about UDP?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you see netcat has bound itself to the port 55823 to send the packets. If we use &lt;a href="https://www.wireshark.org/" rel="noopener noreferrer"&gt;Wireshark&lt;/a&gt; to intercept the packets, we will see this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe0e5gvrshwgl724nodus.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe0e5gvrshwgl724nodus.png" alt="Both UDP datagrams are intercepted by Wireshark" width="800" height="560"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Quick Wireshark tutorial. At the top there is a log of the packets. Below there is a parsed data of the chosen packet. Note that all the data surrounded by square brackets is calculated by Wireshark and does not exist in the packet “as is”. Finally, at the bottom there is a text representation of the packet.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;By the way, if you don’t want to set up Node.js server and capture the communication yourself, feel free to use our &lt;a href="https://ucarecdn.com/5d7f52f9-2f09-4060-bd8c-39be5a5c3894/udp.zip" rel="noopener noreferrer"&gt;dump file&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So, what do we see here? The source port is 55823 as netcat picked. The destination port is 8082 as we set it. The length is 48 bytes because the first 8 bytes are occupied by the header and the rest is the message we sent. Finally, there is even some checksum set by netcat.&lt;/p&gt;

&lt;p&gt;As you see, there is no answer from the UDP server in the Wireshark log, so the client can’t be sure that the server actually got the datagrams. That’s why UDP is used when it’s fine to lose messages, e.g. for video or audio streaming. It’s possible to use TCP for these purposes, but as you will see in a moment the usage of TCP slows down media streaming.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Well, UDP does not have confirmations but we still can detect unreachable destinations using &lt;a href="https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol" rel="noopener noreferrer"&gt;ICMP&lt;/a&gt;. Try to send UDP requests using netcat without the started server and check the Wireshark logs. &lt;a href="https://ucarecdn.com/a896d2db-12fa-46d6-8732-e84f7964d3c6/21icmpwireshark1.png" rel="noopener noreferrer"&gt;Here’s what you may see there&lt;/a&gt;; here’s the &lt;a href="https://ucarecdn.com/8b5c9d21-c9cf-45cb-a299-255cef15b916/icmp.zip" rel="noopener noreferrer"&gt;dump&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Shameless plug you may want to click on:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://uploadcare.com/features/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fucarecdn.com%2F0226385f-1f01-40c7-aecb-fc704954fbb3%2F-%2Fquality%2Fsmart%2F-%2Fformat%2Fauto%2F" alt="Uploadcare advert: Astrologers proclaim the decade of the Heavy Assets Plague! Amount of unhappy users highly increased." width="1488" height="480"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Transmission Control Protocol
&lt;/h2&gt;

&lt;p&gt;While UDP is simple and connectionless, TCP is complex and connection-oriented. It means that prior to sending the data, client and server establish the connection — they agree on some sort of settings they will use to communicate.&lt;/p&gt;

&lt;p&gt;Unlike datagrams in UDP, packets handled by TCP are called &lt;a href="https://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_segment_structure" rel="noopener noreferrer"&gt;segments&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here’s what TCP does during the communication:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It ensures the order of the packets.&lt;/li&gt;
&lt;li&gt;It ensures the delivery.&lt;/li&gt;
&lt;li&gt;It controls the flow of packets to avoid network nodes congestion.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s a lot of work, so the TCP header’s size is at least 20 bytes. The header includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Source port&lt;/li&gt;
&lt;li&gt;Destination port&lt;/li&gt;
&lt;li&gt;Sequence number&lt;/li&gt;
&lt;li&gt;Acknowledgment number&lt;/li&gt;
&lt;li&gt;Header length (or “Data offset”)&lt;/li&gt;
&lt;li&gt;9 control bits (or “Flags”)&lt;/li&gt;
&lt;li&gt;Window size&lt;/li&gt;
&lt;li&gt;Checksum&lt;/li&gt;
&lt;li&gt;Urgent pointer&lt;/li&gt;
&lt;li&gt;Options&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s a picture to visualize the segment:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvtoqoqraur1o75k46wwg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvtoqoqraur1o75k46wwg.png" alt="Scheme with all the fields described above" width="800" height="1127"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The source port, the destination port and the checksum are the same as the UDP header has. To explain the purpose of the rest header fields let’s create a test server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Field test
&lt;/h3&gt;

&lt;p&gt;Let’s set up a simple TCP server using Node.js (again, using the code from the &lt;a href="https://nodejs.org/docs/latest-v14.x/api/net.html#net_net_createserver_options_connectionlistener" rel="noopener noreferrer"&gt;official docs&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;net&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;net&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;net&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;client connected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;client disconnected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello, client!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// 'connection' is a stream which we can pipe&lt;/span&gt;

  &lt;span class="c1"&gt;// first we pipe to stdout to print messages from the client&lt;/span&gt;
  &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// then we pipe to itself to force this stream to read itself&lt;/span&gt;
  &lt;span class="c1"&gt;// making the incoming messages outcoming&lt;/span&gt;
  &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`server error:\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8082&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;address&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`server listening &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above looks like the UDP server we’ve created earlier, but instead of a straightforward handling of incoming messages, we operate a connection object. This connection object allows us not only to print the messages we get, but also to detect when a client is connecting or disconnecting, and to send some responses back. If you set up HTTP servers earlier you should see the similarities.&lt;/p&gt;

&lt;p&gt;Let’s start the server using this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;node tcp.js
server listening :::8082
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Double colon instead of a “usual” IP means that the server is bound to the localhost using IPv6, but it does not matter for now.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now use netcat to start a TCP connection to the server from another terminal window:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;nc 127.0.0.1 8082
Hello, client!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The string we’ve got here has come from the server when the connection has been successfully established. Here’s what we have in the server logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;node tcp.js
server listening :::8082
client connected
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you see the server got a notification from the client and it knows that the client exists, and this client is going to send something. So let’s send:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;nc 127.0.0.1 8082
Hello, client! &lt;span class="c"&gt;# message from the server&lt;/span&gt;
Hello, server! &lt;span class="c"&gt;# our message&lt;/span&gt;
Hello, server! &lt;span class="c"&gt;# reply from the server&lt;/span&gt;
Hey, stop it!  &lt;span class="c"&gt;# our message&lt;/span&gt;
Hey, stop it!  &lt;span class="c"&gt;# reply from the server&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’ve written a simple echo server, which sends back everything it gets from us.&lt;/p&gt;

&lt;p&gt;Close netcat by pressing Ctrl+C and check the server logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;node tcp.js
server listening :::8082
client connected
Hello, server!
Hey, stop it!
client disconnected
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are two messages we’ve sent earlier and the notification about the disconnection.&lt;/p&gt;

&lt;p&gt;So, how is it possible for the server to know about the connection state while we haven’t sent anything yet? To figure it out let’s use Wireshark again.&lt;/p&gt;

&lt;p&gt;Here’s how all the connection looks there:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffd1iwhukdc9f4nv2wie8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffd1iwhukdc9f4nv2wie8.png" alt="18 entries in the Wireshark log" width="800" height="571"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Again, if you can’t set up a Node.js server by yourself, but want to dive into the logs, feel free to use &lt;a href="https://ucarecdn.com/823231ac-88df-47ce-8a79-de818d3754ff/tcp.zip" rel="noopener noreferrer"&gt;our dump&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That’s a lot! Let’s investigate!&lt;/p&gt;

&lt;h3&gt;
  
  
  Handshake
&lt;/h3&gt;

&lt;p&gt;When a client wants to send data to a server, first they both should establish a connection. This “establishing” is usually called &lt;a href="https://en.wikipedia.org/wiki/Handshake_%28computing%29" rel="noopener noreferrer"&gt;handshaking&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The handshake consists of three steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A client sends a packet called SYN to the server.&lt;/li&gt;
&lt;li&gt;The server sends a packet called SYN-ACK to the client.&lt;/li&gt;
&lt;li&gt;The client sends a packet called ACK to the server.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The names are derived from the flags that are set in TCP headers of these packets. Here’s how the first packet looks in Wireshark:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flourltzx2a4tn2b974h3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flourltzx2a4tn2b974h3.png" alt="SYN flag is set" width="800" height="571"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you see, one of the bit flags is set to 1. This flag is called “Syn,” standing for “Synchronization”.&lt;/p&gt;

&lt;p&gt;TCP is a reliable protocol, which means that the sender is always notified whether or not the recipient has got the packet. To implement this feature TCP specifies special types of packets (such as SYN, ACK, etc) and every TCP header contains two numbers: &lt;em&gt;Sequence number&lt;/em&gt; and &lt;em&gt;Acknowledgment number.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Sequence number refers to the amount of data that the sender of the packet has sent so far. The sequence number is increased by 1 when SYN or FIN flags are set, it’s also increased by the payload size when the payload exists. The number does not include the current packet. Thus, the first packet sent by the client always has a sequence number set to 0.&lt;/p&gt;

&lt;p&gt;Acknowledgment number refers to the amount of data that the sender of the packer has received for far. It’s a mirroring of the sequence number from the opposite side of the connection, but with one step ahead. Thus, the first packet sent by the server has an acknowledgement number set to 1.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Actually, the starting values of those numbers are picked up randomly. But it’s easier to operate on relative values as you may see on the Wireshark screenshot above.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Those numbers are useful because they help to maintain the state of the communication on both sides. Both the server and the client expects to get exact acknowledgement and sequence numbers from the other side. When the actual numbers are not the same as the expected, it means that there is an error somewhere and someone should retransmit the data.&lt;/p&gt;

&lt;p&gt;Here’s how the handshake looks in our case:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvfl2i366i7nind19171d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvfl2i366i7nind19171d.png" alt="Client starts with SYN packet with Seq = x, Ack = 0; server responds with SYN-ACK, Seq = y, Ack = x + 1; client ends the handshake with ACK, Seq = x + 1, Ack = y + 1" width="475" height="610"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the handshake is done, our server knows that there is a client ready to communicate, and the server waits for this communication.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data transfer
&lt;/h3&gt;

&lt;p&gt;When the handshake is done, it is time to send a payload.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj4yfo8xk6j1akoaosfl9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj4yfo8xk6j1akoaosfl9.png" alt="Example of a segment carrying payload in the Wireshark log" width="800" height="571"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you see in the log above, each piece of information sent by one end is ACK-ed by the other using the separate segment.&lt;/p&gt;

&lt;p&gt;It looks simple and straightforward, but that’s because our example is simple. In the real world there are a lot of problems: packages may be lost, the channel may be &lt;a href="https://en.wikipedia.org/wiki/TCP_congestion_control" rel="noopener noreferrer"&gt;congested&lt;/a&gt;, an error might occur, and so on. TCP handles all these situations. How? This is a story for another long series of articles. &lt;a href="https://twitter.com/uploadcare" rel="noopener noreferrer"&gt;Let us know&lt;/a&gt; if you’re interested and we may write about TCP in detail.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;By the way, every packet in the log above has the flag PSH set. This is unusual, and in real life this flag is &lt;a href="https://packetlife.net/blog/2011/mar/2/tcp-flags-psh-and-urg/" rel="noopener noreferrer"&gt;not so commonly used&lt;/a&gt;. This is probably netcat specific behavior.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Termination
&lt;/h3&gt;

&lt;p&gt;When one of the nodes is going to close the connection, it initiates a termination. The process itself looks similar to the connection initiation, but instead of using the SYN flag the ends use the FIN flag.&lt;/p&gt;

&lt;p&gt;Here is the termination in our Wireshark log:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fndtwj74uzjkakp42vota.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fndtwj74uzjkakp42vota.png" alt="Two pair of FIN-ACK &amp;amp; ACK segments" width="800" height="571"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In our case the termination has taken four segments, which is not like the handshake. It works this way because when the connection is terminated, the other party (the server in our case) must first notify the Application Layer about the termination. When the app that is using the connection is ready to close it, then the TCP of the other party sends its FIN packet.&lt;/p&gt;

&lt;p&gt;Due to the fact that nodes “agree” on the termination we are able to listen for such an event in our code above.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;By the way, sometimes termination is triggered by the RST flag instead of FIN. It’s kind of hacky, but it is possible. Also, the RST flag is used for the attack which prevents TCP connection between the nodes. If it sounds interesting to you, check out &lt;a href="https://robertheaton.com/2020/04/27/how-does-a-tcp-reset-attack-work/" rel="noopener noreferrer"&gt;this article by Robert Heaton&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this article we’ve found out that the Internet is built around packet switching, and the core protocol stack is TCP/IP. We have also briefly looked at the two main protocols of the Transport Layer of TCP/IP: the very TCP and UDP.&lt;/p&gt;

&lt;p&gt;In the next article we will dive into Internet Protocol, and we will see how it glues every computer in the world into the biggest network.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published by Igor Adamenko in &lt;a href="https://uploadcare.com/blog/tcp-udp/" rel="noopener noreferrer"&gt;Uploadcare Blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>career</category>
      <category>productivity</category>
      <category>discuss</category>
    </item>
    <item>
      <title>A useful function that does nothing</title>
      <dc:creator>Uploadcare</dc:creator>
      <pubDate>Thu, 19 Jan 2023 17:12:48 +0000</pubDate>
      <link>https://forem.com/uploadcare/a-useful-function-that-does-nothing-1bfk</link>
      <guid>https://forem.com/uploadcare/a-useful-function-that-does-nothing-1bfk</guid>
      <description>&lt;p&gt;This article is a part of the ReturnTrue series. Here we solve &lt;a href="https://alf.nu/ReturnTrue"&gt;ReturnTrue puzzles&lt;/a&gt; and try to explain how we find solutions and why exactly they work.&lt;/p&gt;

&lt;p&gt;The goal is not to show the answers but to dive deep into the elaborate internals of JavaScript and browsers. Yet, we recommend you try to find solutions yourself. It would be more interesting this way, be sure.&lt;/p&gt;

&lt;p&gt;Alright, the disclaimer is over. Let’s continue with an introduction explaining what ReturnTrue is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;ReturnTrue is a set of puzzles. Each of them is a tricky function.&lt;br&gt;
You should pass arguments to such a function, and the result of its evaluation should be &lt;code&gt;true&lt;/code&gt;. Not “truthy value”, but exactly &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/steike"&gt;Erling Ellingsen&lt;/a&gt;, a programmer from Norway, created the game more than six years ago. Kudos to him and all the contributors!&lt;/p&gt;

&lt;p&gt;Finally, let’s start.&lt;/p&gt;
&lt;h2&gt;
  
  
  ID
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;x&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;Easy. The main goal of this task is to explain the rules.&lt;/p&gt;

&lt;p&gt;The solution is obvious:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The game assumes that the shorter solution the better. What is shorter than &lt;code&gt;true&lt;/code&gt;? Not-zero!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two symbols. Not bad.&lt;/p&gt;

&lt;h2&gt;
  
  
  But wait, why is it called “id”?
&lt;/h2&gt;

&lt;p&gt;Glad you asked!&lt;/p&gt;

&lt;p&gt;The title “id” here is not by accident. There is a mathematical term called &lt;a href="https://en.wikipedia.org/wiki/Identity_function"&gt;identity function&lt;/a&gt;. It is a function that returns its argument without changing it.&lt;/p&gt;

&lt;p&gt;To explain when we may use it, let’s assume we want to go through an array of numbers and increase each odd value by 1. Here is how it may look in JavaScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&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;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But even though we use &lt;code&gt;map&lt;/code&gt; here, the code is not “functional” enough. In functional programming, it is more common to use functions, not statements. In other words, programmers say &lt;em&gt;what&lt;/em&gt; to do, not &lt;em&gt;how.&lt;/em&gt; They are trying to be declarative, not to be imperative.&lt;/p&gt;

&lt;p&gt;So, if our code was truly functional, it would look 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="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;when&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isOdd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;inc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here you can see a typical functional way to process data.&lt;br&gt;
We pass data to a pipeline, which transforms it, and returns the result. &lt;em&gt;No more of those nasty statements, my precious!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Usually, a functional programming language has the functions like those we used. For instance, Clojure has &lt;a href="https://clojuredocs.org/clojure.core/identity"&gt;identity&lt;/a&gt;, F# has &lt;a href="https://fsharp.github.io/fsharp-core-docs/reference/fsharp-core-operators.html#id"&gt;id&lt;/a&gt;, Elixir has &lt;a href="https://hexdocs.pm/elixir/master/Function.html#identity/1"&gt;identity/1&lt;/a&gt;, and so on.&lt;/p&gt;

&lt;p&gt;But, JavaScript was not designed as a pure functional language. So, their implementation may look 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;isOdd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&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;when&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cond&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;thenFn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;elseFn&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;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;cond&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;thenFn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;elseFn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;xs&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="nx"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now you see when the function returning its argument may be handy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do we need such a function?
&lt;/h2&gt;

&lt;p&gt;Yeah, it may look weird in the context of front-end development. One may even say that &lt;code&gt;id&lt;/code&gt; function is a kludge from FP world.&lt;/p&gt;

&lt;p&gt;Sure, it may sound like a joke or a “bug” of programming language design. First, you define functions that can not be evaluated without passed arguments (e.g. &lt;code&gt;when&lt;/code&gt; function we defined above). Then, you define more functions to use them as a sticky patch for the previously defined.&lt;/p&gt;

&lt;p&gt;However, the functional programming paradigm is trying to be as close as possible to math. &lt;code&gt;id&lt;/code&gt; function is a normal thing for this field of science.&lt;/p&gt;

&lt;p&gt;It may not be obvious why exactly we need such a function. But, when we work with numbers, we use some special ones like 0 or 1.&lt;br&gt;
When we work with arrays, the special one is an empty array. When we work with functions, we need a “special” one too. It is &lt;code&gt;id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It may look like overhead sometimes, and you may think: &lt;em&gt;"Why not define &lt;code&gt;when&lt;/code&gt; function another way, where &lt;code&gt;elseFn&lt;/code&gt; will not be required?"&lt;/em&gt;. Sure, it’s possible. But explicit is better than implicit.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published by Igor Adamenko in &lt;a href="https://uploadcare.com/blog/purpose-of-id-function/"&gt;Uploadcare Blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>beginners</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>We asked ChatGPT how to use our service. Here is what AI answered</title>
      <dc:creator>Uploadcare</dc:creator>
      <pubDate>Thu, 12 Jan 2023 05:49:48 +0000</pubDate>
      <link>https://forem.com/uploadcare/we-asked-chatgpt-how-to-use-our-service-here-is-what-ai-answered-1jf2</link>
      <guid>https://forem.com/uploadcare/we-asked-chatgpt-how-to-use-our-service-here-is-what-ai-answered-1jf2</guid>
      <description>&lt;p&gt;Welcome to 2023! Here we have chatbots that can easily replace real humans!&lt;/p&gt;

&lt;p&gt;OpenAI launched &lt;a href="https://openai.com/blog/chatgpt/" rel="noopener noreferrer"&gt;ChatGPT&lt;/a&gt; in November 2022. We played with this bot, discovered some appealing applications, and forgot about it.&lt;/p&gt;

&lt;p&gt;But then we thought: “What if we ask ChatGPT to build a file uploader page using Uploadcare?” Why not? It should be entertaining.&lt;/p&gt;

&lt;p&gt;Instead of providing the context to the bot at the start, we decided to play a role of a junior developer. Our “developer” heard something about frontend, HTML, CSS &amp;amp; JS, but they do not know much. This is why they ask a lot of newbie questions. To make it easier to read: our questions are headlines, and ChatGPT’s answers are the normal text. Italic text is our comments on the whole play.&lt;/p&gt;

&lt;p&gt;We used the bot’s answers as is. The only thing we removed is the ubiquitous reminders that the bot is ready for any questions. The bot says it at the end of each reply.&lt;/p&gt;

&lt;p&gt;Let’s get started, huh?&lt;/p&gt;

&lt;h2&gt;
  
  
  How to create a simple HTML webpage with a file input?
&lt;/h2&gt;

&lt;p&gt;Here is a simple HTML webpage with a file input field that allows users to select a file to upload:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;form&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Select a file:&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&amp;lt;br&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;br&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"Submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This HTML code creates a form with a file input field and a submit button. When the user selects a file and clicks the submit button, the form will be submitted and the selected file will be uploaded.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to serve a simple HTML file on localhost to be able to open it in a browser?
&lt;/h2&gt;

&lt;p&gt;To serve an HTML file on localhost, you will need to use a web server. Here are the steps to serve an HTML file on localhost using a simple Python web server:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Install Python: Make sure you have Python installed on your computer. You can check if Python is already installed by opening a terminal and entering the command &lt;code&gt;python --version&lt;/code&gt;. If Python is not installed, you can download and install it from the Python website.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Start the web server: Open a terminal and navigate to the directory that contains your HTML file. Then start the Python web server by entering the following command:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   python &lt;span class="nt"&gt;-m&lt;/span&gt; http.server 8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will start a web server on your local machine that listens on port 8000.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;View the HTML file in your browser: Open a web browser and enter the following URL:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   http://localhost:8000/your_html_file.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace “your_html_file.html” with the name of your HTML file. This will open the HTML file in your browser.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Well it works for now:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffyvvb7heqozbzra1g565.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffyvvb7heqozbzra1g565.png" alt="Browser window where file submitting form is shown: label, file input and submit button" width="800" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Give me code that installs Uploadcare widget on my website, please
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;We are trying to be polite. Never know when AI becomes Skynet!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To install the Uploadcare widget on your website, you will need to add the following code to your HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://ucarecdn.com/libs/widget/3.x/uploadcare.full.min.js"&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will include the Uploadcare widget library in your website.&lt;/p&gt;

&lt;p&gt;Once you have added this script to your HTML, you can then use the widget to allow users to upload files from your website. Here is an example of how you can do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- HTML for file input --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"uploadcare-uploader"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"my_file"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- JavaScript to initialize the widget --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;UPLOADCARE_PUBLIC_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your_public_key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;widget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;uploadcare&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[role=uploadcare-uploader]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the &lt;code&gt;input&lt;/code&gt; element with the &lt;code&gt;uploadcare-uploader&lt;/code&gt; role serves as a placeholder for the widget. The JavaScript code initializes the widget and specifies your Uploadcare public key, which you can find in your account settings.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Again, it works:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5xavhhh2x6kbocgtro0q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5xavhhh2x6kbocgtro0q.png" alt="Browser window with modal popup of Uploadcare widget and its button behind the popup" width="800" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;We tested the widget, it works properly. But this is an old way to install our uploader. Currently we have a &lt;a href="https://uploadcare.com/products/file-uploader/" rel="noopener noreferrer"&gt;beta version of File Uploader&lt;/a&gt;, that is based on &lt;a href="https://uploadcare.github.io/blocks/" rel="noopener noreferrer"&gt;Uploadcare Blocks&lt;/a&gt;. Let’s find out what the bot knows about it!&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  I see on their website, that now they offer something called “Blocks”. How do I create a file uploader using these?
&lt;/h2&gt;

&lt;p&gt;Uploadcare Blocks is a new way to build file uploaders and file handling workflows using pre-built UI components. It allows you to easily add file uploading and file handling functionality to your website or application with minimal code.&lt;/p&gt;

&lt;p&gt;To create a file uploading form using Uploadcare Blocks, you will need to do the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Sign up for an Uploadcare account: Go to the &lt;a href="https://uploadcare.com/" rel="noopener noreferrer"&gt;Uploadcare website&lt;/a&gt; and sign up for an account. You will need to provide your email address and create a password.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install the Uploadcare Blocks library: To use Uploadcare Blocks, you will need to include the Blocks library in your HTML code. You can do this by adding the following script tag to your HTML:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;   &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://ucarecdn.com/libs/blocks/2.x/uploadcare.min.js"&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Add a file input element to your HTML: To create a file uploading form using Uploadcare Blocks, you will need to add a file input element to your HTML code. You can do this by using the following HTML:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;   &lt;span class="nt"&gt;&amp;lt;lr-file-uploader-regular&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"my_file"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/lr-file-uploader-regular&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a file input element that will be used to select and upload files.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Initialize the Uploadcare Blocks library: To initialize the libaby set the Uploadcare public key when using the &lt;code&gt;lr-file-uploader-regular&lt;/code&gt; element. You can use the &lt;code&gt;--cfg-pubkey&lt;/code&gt; attribute as a CSS context property. For example:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;   &lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;lr-file-uploader-regular&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="py"&gt;--cfg-pubkey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;"your_public_key"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace “your_public_key” with your actual Uploadcare public key, which you can find in your account settings. This will set the public key for the file uploader and allow it to connect to the Uploadcare API.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Ha! This time it does not work!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiqrwiv7ezusws6eoehiu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiqrwiv7ezusws6eoehiu.png" alt="Browser window without file uploader and with an error in console saying that uploadcare.min.js can not be loaded due to 403 error" width="800" height="174"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Let’s ask the robot why!&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The link you provide, that should install the library, is broken
&lt;/h2&gt;

&lt;p&gt;I apologize for the broken link. The correct URL for the Uploadcare Blocks library is &lt;a href="https://unpkg.com/@uploadcare/blocks@0.14.3/web/blocks-browser.min.js" rel="noopener noreferrer"&gt;https://unpkg.com/@uploadcare/blocks@0.14.3/web/blocks-browser.min.js&lt;/a&gt;. You should use this URL to include the Blocks library in your HTML code.&lt;/p&gt;

&lt;p&gt;To include the Blocks library in your HTML, you will need to add the following script tag to your HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/@uploadcare/blocks@0.14.3/web/blocks-browser.min.js"&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will include the Blocks library in your HTML, allowing you to use the Blocks library to build file uploaders and file handling workflows.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Well, mister smarty-pants, it looks like you’ve forgot something:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdihogsa5fa5fqjpp8evl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdihogsa5fa5fqjpp8evl.png" alt="Browser window with broken file uploader and a lot of errors in the console related to CSS" width="800" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Thanks, now the script works, but it looks like styles are not loaded. Here’s what I see in the console: “CSS Data error: --icon-upload”. How to fix the styles?
&lt;/h2&gt;

&lt;p&gt;To fix the CSS errors that you are seeing in the console, you will need to include the CSS styles for the Uploadcare Blocks library in your HTML.&lt;/p&gt;

&lt;p&gt;You can do this by adding the following link element to the head of your HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/@uploadcare/blocks@0.14.3/web/file-uploader-regular.min.css"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will include the CSS styles for the Blocks library in your HTML, and should fix the CSS errors that you are seeing in the console.&lt;/p&gt;

&lt;p&gt;Alternatively, you can use the &lt;code&gt;css-src&lt;/code&gt; attribute on the &lt;code&gt;lr-file-uploader-regular&lt;/code&gt; element to specify the URL of the CSS styles for the Blocks library. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;lr-file-uploader-regular&lt;/span&gt;
  &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"my_file"&lt;/span&gt;
  &lt;span class="na"&gt;css-src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/@uploadcare/blocks@0.14.3/web/file-uploader-regular.min.css"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/lr-file-uploader-regular&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;It works!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffnhwdu7jzrc1ds7c9x2p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffnhwdu7jzrc1ds7c9x2p.png" alt="Browser window with a button of the File Uploader beta" width="800" height="185"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;We’ve managed to upload a file using the code the bot suggests:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftwe2vgz1iml7gfhcm2ig.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftwe2vgz1iml7gfhcm2ig.png" alt="Browser window with an uploaded file using the File Uploader beta" width="800" height="343"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Alright. When I uploaded an image to Uploadcare, how do I inject it to the webpage? I also want to resize it to 256×256px
&lt;/h2&gt;

&lt;p&gt;To display an image that you have uploaded to Uploadcare in your webpage, you will need to use an &lt;code&gt;img&lt;/code&gt; element and set the &lt;code&gt;src&lt;/code&gt; attribute to the URL of the image on Uploadcare’s servers.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://ucarecdn.com/image_id/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace “image_id” with the actual ID of the image that you want to display. You can find the ID of the image in the response that the Blocks library returns when you upload the image.&lt;/p&gt;

&lt;p&gt;To resize the image to a specific size, you can use the &lt;code&gt;-/resize/&lt;/code&gt; operation in the URL of the image. For example, to resize the image to 256×256 pixels, you can use the following URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://ucarecdn.com/image_id/-/resize/256x256/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will display a 256×256 pixel version of the image. You can specify any size that you want by changing the values in the &lt;code&gt;resize&lt;/code&gt; operation.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Easy-peasy:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7a7mg5n7jytcx9pxqolw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7a7mg5n7jytcx9pxqolw.png" alt="Browser window with resized image showing" width="800" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Now, let’s sum up our experiment without italic.&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;To be honest, when we started the experiment we did not believe that ChatGPT could deal with it. Sure, it’s a cool toy, and it even knows how to generate code examples related to your problem. But we are surprised that the bot knows a lot about our new features, recent documentation, and so on.&lt;/p&gt;

&lt;p&gt;It feels like you’re talking to an assistant who can google for you.&lt;/p&gt;

&lt;p&gt;After the first rapture had passed, we asked ChatGPT more programming-related questions. We would say that it generates code that &lt;em&gt;looks like it should work.&lt;/em&gt; If you do not know how to solve the problem, the code you get can mislead you because it is too convincing.&lt;/p&gt;

&lt;p&gt;Besides, ChatGPT makes mistakes. In this article, we’ve encountered only one — the broken link. But the more questions you ask, the more connected the bot’s answers are. Sometimes they become too connected and start to affect each other. E.g. ChatGPT adapts replies to the language or programming paradigm you prefer. This “feature” sometimes leads to broken or unoptimized code.&lt;/p&gt;

&lt;p&gt;Anyway, ChatGPT is still a handy tool to use. There are some use cases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;To collect a broad overview of some topics.&lt;/strong&gt; E.g. you may ask about scientific concepts or discoveries. When the bot answers, you may ask about relations to other concepts, key people in the field, and so on. It’s like reading those Wikipedia snippets in Google, but you can get such a snippet for any of your questions. Try: &lt;em&gt;"Tell me, please, what Alan Turing’s most popular paper was about?"&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;To handle interactive chats on your website or app (no way!).&lt;/strong&gt; Or to help a human in a call center to find an answer in a bunch of documentation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;To generate blocks of boring text, like legal documents or official letters.&lt;/strong&gt; Sure, a lawyer should review the output, but the result is not that bad already. Try: &lt;em&gt;"I’m creating an Android game that does not collect any data. It is not even connected to the Internet. Do you mind generating the privacy policy for the game?"&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;To extract SEO keywords from the provided text.&lt;/strong&gt; But we will see what Google thinks about it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;To simplify the description of a complex thing to the desired level.&lt;/strong&gt; E.g. try to copy-paste a science term definition from Wikipedia and ask ChatGPT to simplify it for a second-grade student.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;To solve puzzles together.&lt;/strong&gt; It can solve crosswords with ease. If you try hard, you can even explain the bot Wordle rules and get help with today’s word!&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Finally, if you have a tech company, it’s interesting to see whether the bot can use your service. The result of such a check may trigger you to improve the docs or to clarify the purpose of your product.&lt;/p&gt;

&lt;p&gt;Give it a try, and, who knows, you may find ChatGPT a place in your toolset.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;P.S. By the way, we generated an OpenGraph image and the image you see below via Midjourney, while ChatGPT helped us to write the text on that images. Gosh, what a time to be alive!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published by Igor Adamenko in &lt;a href="https://uploadcare.com/blog/chatgpt-uploadcare/" rel="noopener noreferrer"&gt;Uploadcare Blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devmeme</category>
    </item>
    <item>
      <title>Import maps 101</title>
      <dc:creator>Uploadcare</dc:creator>
      <pubDate>Tue, 10 Jan 2023 20:15:04 +0000</pubDate>
      <link>https://forem.com/uploadcare/import-maps-101-2f28</link>
      <guid>https://forem.com/uploadcare/import-maps-101-2f28</guid>
      <description>&lt;p&gt;As web developers, the use of external libraries saves a lot of time and effort, allowing us to build apps faster and more efficiently. In this article, I will be introducing you to a spec called &lt;a href="https://wicg.github.io/import-maps/" rel="noopener noreferrer"&gt;import maps&lt;/a&gt;, which we can use to control the behavior of importing these libraries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Typically, using external libraries in browsers requires bundlers/build tools such as webpack or browserify, in order to parse the code and allow the use of import statements. The modules which are imported without an absolute or relative URL are known as bare modules. Such modules cannot be imported in the browser without bundle tools. For example, importing the lodash package would be written as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;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;This bare import specifier makes it easier to write and manage code, without having to write absolute or relative URLs of the library.&lt;/p&gt;

&lt;h2&gt;
  
  
  What exactly does import maps solve?
&lt;/h2&gt;

&lt;p&gt;With bundlers and build tools solving the issue with bare imports, you may now wonder what problem import maps actually solves.&lt;/p&gt;

&lt;p&gt;The short answer is: &lt;strong&gt;import maps can be used to load bare modules without the need for bundlers.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The longer explanation is that normally, when code gets bundled together into a large file, import maps can be used to control the behavior of importing libraries. Examples of such behaviors we might want to control include remapping of URL-like specifiers, scoping, dynamic imports, etc. This control allows better caching for module script graphs and better developing performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example usage
&lt;/h2&gt;

&lt;p&gt;Let’s take a look at an example implementation of import maps.&lt;br&gt;
In this tutorial, we will learn how to import a bare module like &lt;a href="https://day.js.org/" rel="noopener noreferrer"&gt;dayjs&lt;/a&gt; without the use of a bundler.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1. Create HTML and JS files
&lt;/h3&gt;

&lt;p&gt;First, let’s create a new HTML page and a script file.&lt;/p&gt;

&lt;p&gt;In the HTML file, let’s import a JavaScript file (still empty though) as a module like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!doctype html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Import maps demo&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./index.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2. Write a simple script in the JavaScript file
&lt;/h3&gt;

&lt;p&gt;Now let’s write something simple that uses dayjs.&lt;br&gt;
For this example, I am writing a script that prints out the current datetime every second:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;dayjs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dayjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;h1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dayjs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YYYY-MM-DD HH:mm:ss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Add an import map to import the library
&lt;/h3&gt;

&lt;p&gt;If you try running the page now, it would not work because the dayjs we imported in the JavaScript file is a bare module.&lt;br&gt;
You will see the following error:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Uncaught TypeError: Failed to resolve module specifier "dayjs". Relative references must start with either "/", "./", or "../".&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So let’s use import maps to resolve this error.&lt;br&gt;
Change the HTML file in this way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!doctype html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Import maps demo&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;

  &lt;span class="c"&gt;&amp;lt;!-- Add this importmap before index.js --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"importmap"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;imports&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dayjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cdn.skypack.dev/dayjs@1.11.5&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="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./index.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: When implementing import maps, ensure that they are added before the first module load is started, in this example, index.js.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now let’s run the page, and our script should be running with no issues:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe3sqsov1vs7uhvcs54gz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe3sqsov1vs7uhvcs54gz.gif" alt="The time is ticking" width="800" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Scopes
&lt;/h2&gt;

&lt;p&gt;Another important aspect to know about Import Maps is scoping, which allows the use of multiple versions of the same package in a specified scope.&lt;/p&gt;

&lt;p&gt;For example, the code below specifies that any module in &lt;code&gt;/src&lt;/code&gt; path will use the &lt;code&gt;https://cdn.skypack.dev/dayjs@1.10.7&lt;/code&gt; package, while anything outside that path will use &lt;code&gt;https://cdn.skypack.dev/dayjs@1.11.5&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"importmap"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;imports&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dayjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cdn.skypack.dev/dayjs@1.11.5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scopes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/src&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dayjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cdn.skypack.dev/dayjs@1.10.7&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="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is useful in the case where you need to work with multiple versions of the same package simultaneously for various reasons,&lt;br&gt;
such as compatibility with other libraries, ensuring legacy systems can still run and so on.&lt;/p&gt;
&lt;h2&gt;
  
  
  VS Code extension
&lt;/h2&gt;

&lt;p&gt;Alternatively, instead of writing our import maps script, we could use the &lt;a href="https://marketplace.visualstudio.com/items?itemName=JSPM.jspm-vscode" rel="noopener noreferrer"&gt;VS Code extension&lt;/a&gt; which can automatically generate, and inject import maps for modules and HTML pages.&lt;/p&gt;
&lt;h2&gt;
  
  
  Other Usages
&lt;/h2&gt;

&lt;p&gt;There are also many other uses of import maps besides allowing bare module imports such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;importing modules within modules;&lt;/li&gt;
&lt;li&gt;allow extension-less imports;&lt;/li&gt;
&lt;li&gt;remapping imports (mapping away hashes).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You may learn more about these useful features in the official documentation.&lt;/p&gt;
&lt;h2&gt;
  
  
  Browser Support
&lt;/h2&gt;

&lt;p&gt;In terms of browser support, at the time of this article, it is supported in Chromium-based browsers only (i.e. Chrome, Edge). More of this information can be found on the image below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7dskpnbsv82duu5c4fsp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7dskpnbsv82duu5c4fsp.png" alt="Browser support table" width="800" height="159"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Polyfills
&lt;/h2&gt;

&lt;p&gt;If you want import maps to be supported in any browser, there is an &lt;a href="https://github.com/guybedford/es-module-shims" rel="noopener noreferrer"&gt;ES Module Shims polyfill&lt;/a&gt; which is compatible with any browser that has baseline ES Module Support (i.e. Edge 17+, Firefox 60+, Safari 10.1+, and Chrome 61+).&lt;/p&gt;

&lt;p&gt;To use it, simply add the polyfill script with an &lt;code&gt;async&lt;/code&gt; attribute, and add an import map or module script below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- import polyfill here --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;async&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://ga.jspm.io/npm:es-module-shims@1.5.16/dist/es-module-shims.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"importmap"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;imports&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://ga.jspm.io/npm:react@18.0.0-rc.0/index.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scopes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://ga.jspm.io/npm:react@18.0.0-rc.0/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object-assign&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://ga.jspm.io/npm:object-assign@4.1.1/index.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="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;react&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;react&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code example is taken from the &lt;a href="https://github.com/guybedford/es-module-shims#usage" rel="noopener noreferrer"&gt;shim repo&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;In this article, we learned about import maps, what problems they can solve, and how to implement them. Thanks for reading, I hope it has been a helpful article in getting you started with import maps!&lt;/p&gt;

&lt;p&gt;You can read more about import maps in the References section below. Please share this article if it is insightful! Cheers!&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/WICG/import-maps" rel="noopener noreferrer"&gt;Import maps proposal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/guybedford/es-module-shims" rel="noopener noreferrer"&gt;ES Module Shims&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://caniuse.com/import-maps" rel="noopener noreferrer"&gt;CanIUse? import maps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://marketplace.visualstudio.com/items?itemName=JSPM.jspm-vscode" rel="noopener noreferrer"&gt;JSPM Generator&lt;/a&gt; (VSCode extension)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Originally published by Victoria Lo in &lt;a href="https://uploadcare.com/blog/import-maps-101/" rel="noopener noreferrer"&gt;Uploadcare Blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>permitchallenge</category>
      <category>discuss</category>
      <category>devrel</category>
    </item>
    <item>
      <title>Basics of the Internet</title>
      <dc:creator>Uploadcare</dc:creator>
      <pubDate>Wed, 28 Dec 2022 16:20:16 +0000</pubDate>
      <link>https://forem.com/uploadcare/basics-of-the-internet-mdh</link>
      <guid>https://forem.com/uploadcare/basics-of-the-internet-mdh</guid>
      <description>&lt;p&gt;There is a great book called “High Performance Browser Networking” by Ilya Grigorik that contains basic knowledge about networking and data transfer optimizations. In this book author &lt;a href="https://hpbn.co/primer-on-latency-and-bandwidth/#id-xesGuDH5" rel="noopener noreferrer"&gt;writes&lt;/a&gt; the following about CDNs:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Content delivery network (CDN) services provide many benefits, but chief among them is the simple observation that distributing the content around the globe, and serving that content from a nearby location to the client, enables us to significantly reduce the propagation time of all the data packets.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;We may not be able to make the packets travel faster, but we can reduce the distance by strategically positioning our servers closer to the users! Leveraging a CDN to serve your data can offer significant performance benefits.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When you think about it, you probably agree with the fact that CDNs make the user experience better, because they speed up website loading. But... wait a minute! How does the CDN do it?&lt;/p&gt;

&lt;p&gt;You might say, &lt;em&gt;“Well, when a user loads files from CDN, they are loaded from the nearest server to this user. Easy-peasy.”&lt;/em&gt; Yeah, but how does it happen if we use the one and only domain name for the content?&lt;/p&gt;

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

&lt;p&gt;In Uploadcare we offer our clients a &lt;a href="https://uploadcare.com/cdn/" rel="noopener noreferrer"&gt;CDN&lt;/a&gt; along with other optimizations, and we know a lot about the technologies that are used to make the content delivery fast, reliable, and secure. In this small series of articles we are going to share this knowledge with you and explain the magic behind the CDN.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wiring the things up
&lt;/h2&gt;

&lt;p&gt;Let us start with basic networking. Let’s say we have two computers that should communicate with each other:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxwbkuwdbluccmb30ontv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxwbkuwdbluccmb30ontv.png" alt="Try to imaging that these shapes are real computers" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The solution is simple — wire them and the job is done:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fllcbmax5t44vfiquka38.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fllcbmax5t44vfiquka38.png" alt="The grey line is an Ethernet cable" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yeah, it works. When computer A wants to send a message to computer B, it transfers the data through the port where the cable is connected to. It’s easy to detect when the communication channel is occupied, because there are only two users of this channel. There’s no problem with addressing due to the same reason.&lt;/p&gt;

&lt;p&gt;However, this solution is hard to scale. What should we do when we have five computers instead of two? Sure, we can connect them to each other, but...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv8297xilz2hn8c06tm4x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv8297xilz2hn8c06tm4x.png" alt="Pentagram!" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You see that communication quickly becomes a problem. It’s easier to summon Satan with these wires rather than build a clear network. Not only do we need a lot more cables now, but also each computer should have four ports. Moreover, when we want to add a new computer to this network, we have to find a way to add a new port to each existing computer! The &lt;em&gt;topology&lt;/em&gt; of this network is way too complex.&lt;/p&gt;

&lt;p&gt;In communication networks &lt;a href="https://en.wikipedia.org/wiki/Network_topology" rel="noopener noreferrer"&gt;topology&lt;/a&gt; is the arrangement of the elements. There are &lt;em&gt;physical&lt;/em&gt; and &lt;em&gt;logical&lt;/em&gt; topologies. Physical topology is the placement of the various components of the network, while logical topology is how data flows within a network.&lt;/p&gt;

&lt;p&gt;In our case, every device is connected to each other, which means that we have a &lt;a href="https://en.wikipedia.org/wiki/Network_topology#Fully_connected_network" rel="noopener noreferrer"&gt;&lt;em&gt;fully connected network&lt;/em&gt;&lt;/a&gt;, physically and logically. To reduce the number of cables we may choose a different topology. For example, each computer may be connected to its neighbors on the left and on the right only:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdtvv7rx8nggc38bbe5wv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdtvv7rx8nggc38bbe5wv.png" alt="Way better. No satanism this time!" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is called a &lt;em&gt;&lt;a href="https://en.wikipedia.org/wiki/Ring_network" rel="noopener noreferrer"&gt;ring network&lt;/a&gt;.&lt;/em&gt; As you see, this type of network does not require too many cables and each computer may have two ports only, but the tradeoff is the necessity of transferring data through the intermediate computers while trying to reach the destination.&lt;/p&gt;

&lt;p&gt;Even though using intermediate computers isn’t that bad, there is a much more important flaw in a ring network. The connection relies on the availability of the nodes. If one node of the ring is broken, then the signal can’t be transferred properly.&lt;/p&gt;

&lt;p&gt;There are different topologies which solve different problems. E.g. instead of using a ring network we might use one central wire to which all the computers are connected. That is, we would get a &lt;em&gt;&lt;a href="https://en.wikipedia.org/wiki/Bus_network" rel="noopener noreferrer"&gt;bus network&lt;/a&gt;:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx01ev74my1g2vy8irwnw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx01ev74my1g2vy8irwnw.png" alt="It looks like a typical USA suburbs road system" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now our network does not rely on computers, but it will be broken if the central wire (usually called a &lt;em&gt;bus,&lt;/em&gt; a &lt;em&gt;backbone&lt;/em&gt; or a &lt;em&gt;trunk&lt;/em&gt;) does not work properly. This type of network is harder to maintain, because you have to be able to check and repair every inch of the backbone.&lt;/p&gt;

&lt;p&gt;To solve the maintenance problem described above, we may use a “helper device” which will receive data from a computer and distribute it through the network. The device is called a &lt;em&gt;hub,&lt;/em&gt; while the topology of this kinds of network is called a &lt;em&gt;&lt;a href="https://en.wikipedia.org/wiki/Star_network" rel="noopener noreferrer"&gt;star&lt;/a&gt;:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fne2k958xmsp29bxhyo7w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fne2k958xmsp29bxhyo7w.png" alt="Stellar thing in the center is a hub" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even though this network may be broken by shutting down the hub, it’s much easier to maintain — instead of controlling a long cable, we have to control only one device. Also, it’s much easier to connect new nodes — just plug the cable into the hub, and it works.&lt;/p&gt;

&lt;p&gt;In real life we use star networks at home. All the devices are usually connected to one router that receives messages and distributes them when necessary. The Internet itself is a &lt;em&gt;hybrid network,&lt;/em&gt; which is combined from the myriads of small networks, each one of those may use any physical or logical topology.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Internet hierarchy
&lt;/h2&gt;

&lt;p&gt;Alright, we have a network at home that may look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyvspoyuk9wg2qyalk4qg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyvspoyuk9wg2qyalk4qg.png" alt="Hope you don’t really have a fridge with Wi-Fi though" width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But what happens on the next level? What is the way of your request to Google? Let’s see.&lt;/p&gt;

&lt;p&gt;First of all, your request will land on the computer that will process it — a Google server:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fecl8brus5ciee69huj8s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fecl8brus5ciee69huj8s.png" alt="Yeah, I know, my drawing skills are blessed by God" width="800" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But the request doesn’t go straight to the Google server.&lt;/p&gt;

&lt;p&gt;Your router connects you with a larger network owned by your &lt;a href="https://en.wikipedia.org/wiki/Internet_service_provider" rel="noopener noreferrer"&gt;&lt;em&gt;Internet Service Provider&lt;/em&gt;&lt;/a&gt; &lt;em&gt;(ISP).&lt;/em&gt; Same goes with the Google’s computer:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvj7crpf7ozcsl49epr7f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvj7crpf7ozcsl49epr7f.png" alt="By the way, usually a home router is not connected directly to an ISP. There are more routers and other devices between them" width="800" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each of those ISPs maintains its own network for many of the local networks, not only for yours and Google’s.&lt;/p&gt;

&lt;p&gt;If you are connected to the same ISP as your Google server — you’re lucky, because the data may be transferred inside the provider’s network which is fast, secure and reliable:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsjrtg559fnj926b6wwuo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsjrtg559fnj926b6wwuo.png" alt="Eh.. Sergey? Larry?" width="800" height="228"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But in the real world it is not possible to connect everyone using only one ISP. There are hundreds and thousands of providers. Each ISP has to communicate with each other to make the Internet work properly.&lt;/p&gt;

&lt;p&gt;So, the closest to real life example may look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feyjhzak9tv5d36adqfa1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feyjhzak9tv5d36adqfa1.png" alt="In reality even this scheme is not possible" width="800" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You might see the problem here. If all the ISPs should connect to each other directly then we may encounter the same situation we got at the start of this article — tons of wire! That’s why they are connected using hubs called &lt;em&gt;&lt;a href="https://en.wikipedia.org/wiki/Internet_exchange_point" rel="noopener noreferrer"&gt;Internet Exchange Points&lt;/a&gt;,&lt;/em&gt; or &lt;em&gt;IXPs&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn49w88dnzev4ac393xyw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn49w88dnzev4ac393xyw.png" alt="If we continue adding entities to this scheme, we will run out of shapes. Please, send halp" width="800" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our network is already complicated, but there is one more problem — geography.&lt;/p&gt;

&lt;p&gt;What if you live in Spain, while the Google computer “lives” in the USA? Well, they should be connected in some way, right?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb40moeqk0exisad0u5yu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb40moeqk0exisad0u5yu.png" alt="Color coding is the same; we simply put the network on the map" width="800" height="284"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This way is an underwater cable! You may think that this is a joke, but no, it is not. The continents are connected to each other using &lt;a href="https://en.wikipedia.org/wiki/Submarine_communications_cable" rel="noopener noreferrer"&gt;undersea cables&lt;/a&gt;. It may seem unreliable, and in fact &lt;a href="https://www.theguardian.com/business/2008/feb/01/internationalpersonalfinancebusiness.internet" rel="noopener noreferrer"&gt;sometimes it is&lt;/a&gt;. But it’s still the best way to connect everything:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkhpvlnmz3pv03ppp235s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkhpvlnmz3pv03ppp235s.png" alt="The cable is not that thick though" width="800" height="285"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now it looks like we know how to connect two computers using the Internet. But here’s where things become really mad.&lt;/p&gt;

&lt;p&gt;First, there are lots of ISPs.&lt;/p&gt;

&lt;p&gt;Second, there are lots of IXPs.&lt;/p&gt;

&lt;p&gt;Third, there are lots of undersea cables! Check the &lt;a href="https://www.submarinecablemap.com/" rel="noopener noreferrer"&gt;map of them&lt;/a&gt; dated 2021:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqormeuiz409r13l1zwpl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqormeuiz409r13l1zwpl.png" alt="At the moment when we’re writing this article, there are 485 cables laying in the oceans" width="800" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, not every ISP is connected directly to IXP. Sometimes they are connected to “parent” ISPs.&lt;/p&gt;

&lt;p&gt;Even this is not the end, the cables are different: some of them transmit the signal faster, others do it slower. What’s more important, some of them cost more than others to use. You don’t think that the connection between ISPs and IXPs is free of charge, do you? ISPs pay to each other and IXPs to use the network each of them have. Some providers charge more, others charge less.&lt;/p&gt;

&lt;p&gt;That’s why the signal your computer sends usually does not go by the shortest path. The signal goes by the cheapest one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Transmission medium
&lt;/h2&gt;

&lt;p&gt;A &lt;em&gt;transmission medium&lt;/em&gt; is a system or substance we use to transfer the signal. When devices are connected to each other using Wi-Fi, the medium is air. When your PC is connected to your router, the medium is usually a &lt;a href="https://en.wikipedia.org/wiki/Twisted_pair#Unshielded_twisted_pair" rel="noopener noreferrer"&gt;copper wire&lt;/a&gt;. The backbone of the Internet — the undersea cables — is made of &lt;a href="https://en.wikipedia.org/wiki/Optical_fiber" rel="noopener noreferrer"&gt;optic fiber&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The medium defines the conditions in which the communication can be done.&lt;/p&gt;

&lt;p&gt;For instance, copper wires are affected by any electrical noise. That’s why the twisted pair is actually “twisted” — to prevent electromagnetic interference. Such cables also may be &lt;a href="https://en.wikipedia.org/wiki/Shielded_cable" rel="noopener noreferrer"&gt;covered&lt;/a&gt; with a special material which “shields” the transmitted signal.&lt;/p&gt;

&lt;p&gt;At the same time, optical fiber does not care about electrical noise, because it’s just a “light pipe.” Even more, due to the techniques used to transfer the data, the speed of transmission may be &lt;a href="https://en.wikipedia.org/wiki/Fiber-optic_communication#Record_speeds" rel="noopener noreferrer"&gt;much higher&lt;/a&gt; in optical fiber than in copper wire!&lt;/p&gt;

&lt;p&gt;Now you may say, “The Internet is based on undersea cables and this is kinda sick. Why not use satellites if we can transmit data through the air?”&lt;/p&gt;

&lt;p&gt;Sure, it is possible to connect computers using satellites. E.g. GPS uses satellites and it works. First of all, it’s cheaper to simply wire the computers up. Besides, the network laying on the ground (or in the sea) is much easier to repair.&lt;/p&gt;

&lt;p&gt;Moreover, let’s do the quick math. Let’s recall the connection we described earlier. Let’s say that the orange dot was Nashville, USA, while the white dot was Zaragoza, Spain:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyoir01tv9yvvsmls7rw2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyoir01tv9yvvsmls7rw2.png" alt="According to this map our ISP’s office is somewhere in Iberian System, huh" width="800" height="285"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The distance between these cities is 7200 kilometers. If we connect them using a direct wire, the signal transmitted from Zaragoza will reach Nashville in 36 milliseconds, because the speed of light in optic fiber is around 200 000 km/s (it’s 1.5 lower than in the vacuum).&lt;/p&gt;

&lt;p&gt;At the same time, there might be a satellite somewhere in the middle of the sky, between Zaragoza and Nashville. Historically, communication satellites were deployed on &lt;a href="https://en.wikipedia.org/wiki/Geostationary_orbit" rel="noopener noreferrer"&gt;geostationary orbit&lt;/a&gt;, the altitude of which is 35 786 kilometers. Our signal should go from Zaragoza to the satellite and then from the satellite to Nashville.&lt;/p&gt;

&lt;p&gt;Let’s omit trigonometry and say that the total distance is 2 × 35 786 kilometers, which is 71 572 km.&lt;/p&gt;

&lt;p&gt;At the same time, the speed of the signal that goes to the satellite and back is approximately 300 000 km/s, because &lt;a href="https://en.wikipedia.org/wiki/Radio_wave" rel="noopener noreferrer"&gt;radio waves&lt;/a&gt; are used for transferring the signal. The total trip time is 238 ms.&lt;/p&gt;

&lt;p&gt;So, the time that signal goes from Zaragoza to Nashville by direct wire is 36 milliseconds. For the satellite this time is 238 ms.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;We have not said anything about the fact that all those intermediate points, such as ISPs, IXPs and the rest of them, slows the signal down, making the real transferring time bigger than 36 ms. But at the same time, we haven’t said anything about the quality of the signal, which is usually not so good for transmissions over the air.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So, you see why the world is still using cables. In the foreseeable future, the status quo may change, due to massive deployment of satellites (e.g. by Starlink) to a &lt;a href="https://en.wikipedia.org/wiki/Low_Earth_orbit" rel="noopener noreferrer"&gt;low Earth orbit&lt;/a&gt;. Lower altitude allows the satellites to maintain a connection with &lt;a href="https://www.reddit.com/r/Starlink/comments/i9w09n/list_of_confirmed_starlink_speed_tests/" rel="noopener noreferrer"&gt;much less&lt;/a&gt; latency.&lt;/p&gt;

&lt;p&gt;However, it’s highly unlikely that the current wired infrastructure disappears, which means that if you maintain an Internet service you have to use services like CDNs to serve data closer to users.&lt;/p&gt;

&lt;p&gt;In the next article of this series we will see how the signal is encoded during the transfer and figure out how to intercept requests to inspect them.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally &lt;a href="https://uploadcare.com/blog/basics-of-the-internet/" rel="noopener noreferrer"&gt;published&lt;/a&gt; by Igor Adamenko in Uploadcare Blog&lt;/em&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Service workers tutorial</title>
      <dc:creator>Uploadcare</dc:creator>
      <pubDate>Mon, 26 Dec 2022 00:19:12 +0000</pubDate>
      <link>https://forem.com/uploadcare/service-workers-tutorial-1b7h</link>
      <guid>https://forem.com/uploadcare/service-workers-tutorial-1b7h</guid>
      <description>&lt;p&gt;Web developers or anyone involved in web development can tell you they know of “workers” in browsers. However, the problem is that most folks think of either web workers in general, or service workers (or even shared workers) when they say “workers.” These terms can be confusing, especially if you didn’t come across them.&lt;/p&gt;

&lt;p&gt;That is why today, we will dive into service workers. We’ll see why you’d want to use service workers, what they are, how they work and explain the difference between service workers and other workers in the browser.&lt;/p&gt;

&lt;p&gt;Before we start, let’s dive in and see what the web workers are in general.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are web workers?
&lt;/h2&gt;

&lt;p&gt;A &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Worker" rel="noopener noreferrer"&gt;web worker&lt;/a&gt; is a background task defined via script — a JavaScript file. Web workers can communicate back and forth with their creator. A web worker runs in a separate thread from the main JavaScript thread. To see how they work and get a small introduction to the world of web workers, let us go through a simple example.&lt;/p&gt;

&lt;p&gt;You can create a web worker in the application code like so:&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;myAwesomeWorker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/path/to/worker.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, you can communicate with the worker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;myAwesomeWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hi there, love you&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 web worker, you can accept the message and respond back to the caller:&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;// /path/to/worker.js&lt;/span&gt;

&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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 some magic here&lt;/span&gt;
  &lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;I am all done, back to you, main application code.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, the caller can listen to the messages from the web worker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;myAwesomeWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Message received from myAwesomeWorker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Above is a trivial example of how web workers work, but it should be a great start to our topic where we will explore a specialized worker — service worker. To summarize, a web worker is a JavaScript file that runs in a different thread, but still can communicate with our application code. We can communicate with the web worker back and forth, and it can be a great helper when we want to delegate work away from the main thread of our application.&lt;/p&gt;

&lt;p&gt;Now that we got over the basics, let’s see what service workers are.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are service workers?
&lt;/h2&gt;

&lt;p&gt;A service worker is a mediator between the web application, the browser, and the network. The service worker is like a proxy server that sits between your application and the network, intercepting requests and serving the corresponding responses.&lt;/p&gt;

&lt;p&gt;You can also envision a service worker as a middleware for your site. Any request from the site and any response it gets goes through the service worker. Besides being a middleware, service workers also have access to a cache, where they can save responses and assets.&lt;/p&gt;

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

&lt;p&gt;All this makes a perfect scenario if you’re planning to add exceptional offline support to your website. A service worker can decide if it should serve a resource from the cache or the network, as it would happen without a service worker. However, it is important to note that not all browsers support service workers. We should make service workers an enhancement rather than a requirement for our website.&lt;/p&gt;

&lt;p&gt;One more use case can be the ability to use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Push_API" rel="noopener noreferrer"&gt;Push API&lt;/a&gt; to receive notifications from the server. This API provides the option for developers to deliver asynchronous messages and updates to users who opt in, resulting in better engagement with timely new content. For example, you can build a service worker that will update users when a new app is available.&lt;/p&gt;

&lt;p&gt;OK, now that we understand the concept of service workers, let’s see what a typical lifecycle of a service worker is.&lt;/p&gt;

&lt;h2&gt;
  
  
  The service worker lifecycle
&lt;/h2&gt;

&lt;p&gt;To fully understand how service workers behave, we must understand the different states they can exist in. To use a service worker, we have to register it on the client side. Here’s how we can do it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;serviceWorker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/myServiceWorker.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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we do a simple check to see if service workers are supported in the user’s browser. Then, we call &lt;code&gt;navigator.serviceWorker.register&lt;/code&gt; with the path to our service worker JavaScript file.&lt;/p&gt;

&lt;p&gt;Then, we have to distinguish two use cases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When we register a service worker for the first time&lt;/li&gt;
&lt;li&gt;When we update the existing service worker&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1. Registering a service worker for the first time
&lt;/h3&gt;

&lt;p&gt;In the first scenario, where the page doesn’t have any service workers, the client will attempt to download the service worker we registered. After the download, the browser will try to install the service worker. After successful installation, the service worker is then activated and ready to perform.&lt;/p&gt;

&lt;p&gt;To sum up the first case, the lifecycle looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download (parse, and execute)&lt;/li&gt;
&lt;li&gt;Install&lt;/li&gt;
&lt;li&gt;Activate&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  2. Updating existing service worker
&lt;/h3&gt;

&lt;p&gt;Now, in the second use case where we want to update the existing service worker, we might get into an extra state between installing and activating. If an existing service worker is available, the installation for the new worker is done in the background. Once the installation is complete, the new worker is not yet activated.&lt;/p&gt;

&lt;p&gt;The worker now needs to wait for when there are no longer any pages loaded that are still using the old service worker. As soon as there are no more pages to be loaded, the new service worker activates (becoming the active worker). You can skip the waiting for the new worker using &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/skipWaiting" rel="noopener noreferrer"&gt;&lt;code&gt;ServiceWorkerGlobalScope.skipWaiting()&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So when the service worker is updated, this is how its lifecycle looks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download&lt;/li&gt;
&lt;li&gt;Install&lt;/li&gt;
&lt;li&gt;Wait&lt;/li&gt;
&lt;li&gt;Activate&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We talked about how to register a service worker, and how browsers later activate it. But how does the lifespan of a service worker end?&lt;/p&gt;

&lt;p&gt;It’s important to note that service workers don’t live indefinitely. While exact timings differ between browsers, service workers will be terminated if they’ve been idle for a few seconds, or if they’ve been busy for too long. If a service worker has been terminated and an event occurs that may start it up, it will be restarted.&lt;/p&gt;

&lt;p&gt;All in all, the service worker lifecycle can be shown in one diagram:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnjde5l5t888ow1ihaxy6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnjde5l5t888ow1ihaxy6.png" width="481" height="691"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OK, now that we got through the basics on how to register a service worker and its whole lifecycle in the browser, let’s go on and see how it works. We’re going to create a service worker that caches our requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using service worker to cache requests
&lt;/h2&gt;

&lt;p&gt;One of the most common use cases for service workers is that they are used to cache assets and requests on your website. They are a fundamental part if you’re looking into making a &lt;a href="https://web.dev/progressive-web-apps/" rel="noopener noreferrer"&gt;Progressive Web App&lt;/a&gt; (PWA). As we mentioned before, when registered, the service worker acts as a layer between your website and the network. The worker intercepts every request from your website out to the world.&lt;/p&gt;

&lt;p&gt;In addition to being a middleware between your website and the world, a service worker can utilize the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage" rel="noopener noreferrer"&gt;Cache Storage API&lt;/a&gt;. In this example, we will use just that — a simple service worker that caches requests in the browser’s cache. This API works similarly to the browser’s standard cache, but it is specific to your domain. You have full control over the API, meaning you can control when the keys expire and add new keys. It’s important to mention that the service worker’s storage is independent of the browser HTTP cache to ensure we don’t mix the two.&lt;/p&gt;

&lt;p&gt;Without further ado, let us go into how we can cache our resources with service workers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caching assets on service worker’s installation
&lt;/h2&gt;

&lt;p&gt;Before our service worker is fired, we need to register it on a page. We will use a similar code we used in the lifecycle section:&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;registerWorker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;serviceWorker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;registration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/worker.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Service worker registration succeeded:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;registration&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Registration failed with &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nf"&gt;registerWorker&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we will check whether service workers are supported in the context where our code runs with &lt;code&gt;'serviceWorker' in navigator&lt;/code&gt; check. After that, we’ll do &lt;code&gt;navigator.serviceWorker.register('/worker.js')&lt;/code&gt; which will register the &lt;em&gt;worker.js&lt;/em&gt; file as our service worker. After that, we’ll write to the browser console, to ensure everything gets set up correctly. If there were an error somewhere, our try/catch block would take care of that.&lt;/p&gt;

&lt;p&gt;Also, it is good to note that every service worker has a configurable scope. You can set scope when registering a script to be a service worker like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;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="na"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/some-scope&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you omit scope, it will use the default value. The default value of the scope depends on where the service worker got registered. If you register a service worker under &lt;em&gt;domain.com/index.html,&lt;/em&gt; the worker will control &lt;em&gt;domain.com/index.html&lt;/em&gt; and all pages underneath. If you change the scope to something else like below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;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="na"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/blog/&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;And, if you register the service worker in the &lt;em&gt;domain.com/index.html,&lt;/em&gt; then it will control only the &lt;em&gt;domain.com/blog/&lt;/em&gt; portion of it.&lt;/p&gt;

&lt;p&gt;Great, now that we registered our service worker and understand the concept of a worker’s scope — let us define some logic in the service worker file &lt;em&gt;worker.js.&lt;/em&gt; Here’s how it will look:&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;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;v1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;addResourcesToCache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;caches&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;);&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="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;install&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; installing...`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;addResourcesToCache&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;/index.html&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;/styles.css&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;/script.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/jungle.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the top, we first declare the version to be &lt;code&gt;v1&lt;/code&gt; — we’ll get to this in a second. Then, we define the &lt;code&gt;addResourcesToCache&lt;/code&gt; function that opens a Cache Storage instance and writes to it with:&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;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;caches&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;caches.open&lt;/code&gt; receives a string that represents a cache name. Later on, as we change our service worker, we will have to change the name of the cache and remove the old one, but we’ll get to that in a second.&lt;/p&gt;

&lt;p&gt;So if we open our page now, the service worker defined in &lt;em&gt;worker.js&lt;/em&gt; will install and cache our resources. To be sure it happened, we can check the “Applications” tab in Google Chrome. If we open the “Storage” section there, we will see how much storage our website is taking:&lt;/p&gt;

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

&lt;p&gt;Also, we can go into “Cache Storage” and check the &lt;code&gt;v1&lt;/code&gt; cache we just created in our service worker. In “Cache Storage,” you should see the resources we specified:&lt;/p&gt;

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

&lt;p&gt;Cool, we got our website’s assets in the service worker cache, safely away from the standard browser cache. But, what now, you must be asking? Now, we need to tell the browser to serve those assets from the cache. And a great way to do that is to use our service worker.&lt;/p&gt;

&lt;h2&gt;
  
  
  Serving assets from the cache
&lt;/h2&gt;

&lt;p&gt;We will listen for a &lt;code&gt;fetch&lt;/code&gt; event in our worker, and intercept requests going from our website to the network. Here’s how it looks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respondWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;caches&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&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;With this code, we are hijacking each request firing from our site. Then, we call &lt;code&gt;respondWith&lt;/code&gt; and respond with a cached value in our cache. If we add this code, close and then reopen our website, and open the “Network” tab in a browser. We will see that the resources are cached in by the service worker:&lt;/p&gt;

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

&lt;p&gt;This is all fine and dandy, but if we add a resource to our site or remove a resource from the cache manually, our site can break.&lt;/p&gt;

&lt;p&gt;For example, I tried to remove &lt;em&gt;styles.css&lt;/em&gt; from the cache in “Application” → “Cache Storage,” and the CSS went missing the next time I opened the page. Neither worker nor the browser fetched &lt;em&gt;styles.css&lt;/em&gt; again because of the logic in the worker. To mitigate this, we have to make sure that a request gets passed through our service worker if there’s no matching resource in our cache. Here’s how we can do that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const cacheFirst = async (request) =&amp;gt; {
  const responseFromCache = await caches.match(request);

  if (responseFromCache) {
    return responseFromCache;
  }

  return fetch(request);
};

self.addEventListener('fetch', (event) =&amp;gt; {
  event.respondWith(cacheFirst(event.request));
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the new &lt;code&gt;cacheFirst&lt;/code&gt; function, we are sure that a request that is not in the cache will get sent out to the network with &lt;code&gt;fetch(request)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can go a step further, and cache requests that are not in the cache. That way, we will fetch a resource from the network, and store it into the cache. If our app goes offline for some reason, that resource will still be available, yay! This is what our &lt;code&gt;fetch&lt;/code&gt; event handler should look 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;putInCache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;caches&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cannot cache non-GET requests&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cacheFirst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;responseFromCache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;caches&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;responseFromCache&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;responseFromCache&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;responseFromNetwork&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// we need to clone the response because the response stream can only be read once&lt;/span&gt;
  &lt;span class="nf"&gt;putInCache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;responseFromNetwork&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clone&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;responseFromNetwork&lt;/span&gt;&lt;span class="p"&gt;;&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="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respondWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cacheFirst&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we define the &lt;code&gt;putInCache&lt;/code&gt; function that puts the request and its response into the cache.&lt;/p&gt;

&lt;p&gt;If you notice, we also check for a request method. By design, we cannot cache non-GET requests in the Cache Storage API. After that, we changed the &lt;code&gt;cacheFirst&lt;/code&gt; function to call the &lt;code&gt;putInCache&lt;/code&gt; function with the request object and the clone of a response. We have to clone the response, because request and response streams can only be read once. Then, we return the original response to the browser.&lt;/p&gt;

&lt;p&gt;And that is it, this is the basic service worker that will cache all GET requests that go from your website to the network. This setup can be a great first step if you plan to make your app work offline. You can play around with different caching strategies, let’s quickly go over them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cache-First
&lt;/h3&gt;

&lt;p&gt;We implemented here a cache-first approach, where we first try to serve a request from the cache if it is available.&lt;/p&gt;

&lt;h3&gt;
  
  
  Network-First
&lt;/h3&gt;

&lt;p&gt;You can try and implement a network-first approach, where we normally send out the request to the network and cache it. Then, when the request can’t be made (the site lost connectivity, for example) — we serve the failed request from the cache.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stale-While-Revalidate
&lt;/h3&gt;

&lt;p&gt;There’s also a stale-while-revalidate approach that will use a cached version if available, but it will fetch an update and put it in the cache for next time.&lt;/p&gt;

&lt;p&gt;We could also go on and make sure that a user gets a fallback response, in case the resource is not in the cache and it can’t be fetched over the network. But this should be enough to get you started on a service worker. Instead, I’d like us to compare the difference between service workers and workers in general. Let’s dive into that in the next section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Service workers versus other workers
&lt;/h2&gt;

&lt;p&gt;Now that we have an understanding of service workers, we can look over other types of web workers, and how they differ from each other. Let’s start with how similar web workers and service workers are.&lt;/p&gt;

&lt;p&gt;Web workers and service workers are two different types of background scripts available to websites in the browser. Both web workers and service workers have some things in common:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;They both run in a different thread without blocking the main JavaScript thread and the user interface.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;They can’t interact with the DOM directly, and they have limited access to browser APIs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;They both are web workers. But service workers are just a specialized version of web workers.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the differences between them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;As we mentioned before, service workers allow you to intercept network requests (via the &lt;a href="https://developer.mozilla.org/docs/Web/API/FetchEvent" rel="noopener noreferrer"&gt;&lt;code&gt;fetch&lt;/code&gt;&lt;/a&gt; event), and to listen for Push API events in the background (via the &lt;a href="https://developer.mozilla.org/docs/Web/API/PushEvent" rel="noopener noreferrer"&gt;&lt;code&gt;push&lt;/code&gt;&lt;/a&gt; event). Web workers can’t do that.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A page can spawn multiple web workers, but only one service worker controls all the active tabs under the scope it was registered with.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The lifespan of the web worker is tightly coupled to the tab it belongs to, while the service worker’s lifecycle is independent of it. When you close the tab where a web worker is running, the worker will be terminated. A service worker can continue running in the background, even when the site that registered it doesn’t have any active tabs open.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Service workers only run over HTTPS for security reasons. Being able to modify network requests, they are wide open to man-in-the-middle attacks, which is why they are only allowed on secure connections. In Firefox, Service Worker APIs are also hidden, and cannot be used when the user is in private browsing mode. There’s an &lt;a href="https://github.com/nikolalsvk/uploadcare-writing/blob/service-workers/a-guide-to-service-workers/mozilla.org/show_bug.cgi?id=1320796" rel="noopener noreferrer"&gt;open bug&lt;/a&gt; for that if you want to track it.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are also &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker" rel="noopener noreferrer"&gt;shared workers&lt;/a&gt;. They are workers that can be utilized by multiple scripts running in different windows, iframes, and similar, as long as they are in the same domain as the worker. The scripts must communicate via an active port, so they are more complex than the standard workers or service workers.&lt;/p&gt;

&lt;p&gt;Besides these, you can also utilize &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Worklet" rel="noopener noreferrer"&gt;worklets&lt;/a&gt;. A worklet interface is a lightweight version of web workers, and gives developers access to low-level parts of the rendering pipeline. Worklets can be used to run JavaScript and WebAssembly code to perform graphics rendering or audio processing, where high performance is required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summing up
&lt;/h2&gt;

&lt;p&gt;Phew, what a ride. We learned the basics of service workers, but let’s go over it once again. Here are things to remember:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A service worker is a specialized worker that performs away from the main JavaScript thread.&lt;/li&gt;
&lt;li&gt;A service worker can act as middleware between your site and the network.&lt;/li&gt;
&lt;li&gt;To have a service worker on your website, it has to be first downloaded, installed, and then activated.&lt;/li&gt;
&lt;li&gt;If you’re updating an existing service worker, the previous service worker must be unloaded from the page (or you can instead skip waiting for that).&lt;/li&gt;
&lt;li&gt;Service workers only run over HTTPS for security reasons.&lt;/li&gt;
&lt;li&gt;One of the main use cases for a service worker is to cache resources.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As far as web workers are concerned, they are mostly used to delegate work from the main thread while the page is open. As soon as the page is closed, the classic worker is terminated as well.&lt;/p&gt;

&lt;p&gt;If you’re interested in the code from this blog post, I pushed it to a &lt;a href="https://github.com/nikolalsvk/service-worker-jungle" rel="noopener noreferrer"&gt;repository on GitHub&lt;/a&gt;. You can check it out there, it has a small index.html page that showcases how you can cache resources.&lt;/p&gt;

&lt;p&gt;That’s all folks, next time, we will go into how to debug service workers (even though we showed a glimpse of where you can do that), and we can show how to use service workers in some other use case.&lt;/p&gt;

&lt;p&gt;Until then, thanks for reading, and catch you in the next one.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally &lt;a href="https://uploadcare.com/blog/service-workers-tutorial/" rel="noopener noreferrer"&gt;published&lt;/a&gt; by Nikola Đuza in Uploadcare Blog&lt;/em&gt;&lt;/p&gt;

</description>
      <category>gratitude</category>
    </item>
    <item>
      <title>Creating responsive images with image-set</title>
      <dc:creator>Uploadcare</dc:creator>
      <pubDate>Thu, 22 Dec 2022 00:05:19 +0000</pubDate>
      <link>https://forem.com/uploadcare/creating-responsive-images-with-image-set-4kci</link>
      <guid>https://forem.com/uploadcare/creating-responsive-images-with-image-set-4kci</guid>
      <description>&lt;p&gt;&lt;code&gt;image-set&lt;/code&gt; is a CSS function that allows you to make an image responsive, showing variations of the same picture for different screen resolutions when needed. This function is almost the same as the HTML &lt;code&gt;srcset&lt;/code&gt; attribute for &lt;code&gt;img&lt;/code&gt; tags.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are responsive images?
&lt;/h2&gt;

&lt;p&gt;Simply put, images are &lt;em&gt;responsive&lt;/em&gt; when they display the information they are intending to regardless of the screen size or pixel resolution. This is to say; these images automatically adjust themselves to fit the size of the container they’re placed into, and load according to the resolution of the user’s screen. This process improves the user experience, as images load faster and look crisper to the human eye.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why responsive images?
&lt;/h2&gt;

&lt;p&gt;Why not? Here are three essential reasons why we should always make our web images responsive:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;To render high-quality images on different devices. Also known as &lt;em&gt;resolution switching.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To load the right images on different screen sizes. Also known as &lt;em&gt;art direction.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For faster loading of web pages.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s discuss a little about each of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resolution switching
&lt;/h2&gt;

&lt;p&gt;A digital screen uses pixels to display images. These pixels are arranged horizontally and vertically in a grid. The number of pixels both horizontally and vertically, is known as the screen resolution.&lt;/p&gt;

&lt;p&gt;For example, a “screen with a 1024×768 resolution” means that the screen has 1024 pixels horizontally, and 768 pixels vertically. An image with a 1024×768 resolution also has 1024 pixels horizontally and 768 pixels vertically, making them have the same width and height.&lt;/p&gt;

&lt;p&gt;If we insert such an image into the page, and set its width and height to 100% of the user’s screen, it will be nice looking on 1024×768 screen. However, the same image would be stretched on a screen with a 2048×1536 resolution, because the screen’s width and height are higher, and we would be showing fewer image’s pixels in a larger space. So on a smaller screen, the image will look sharper because you are showing many pixels in a smaller space.&lt;/p&gt;

&lt;p&gt;Image pixel resolutions also partly determine the image size, and the size of an image can affect how fast a browser loads a web page and the amount of data the user uses to download it. For example, a 150×100 image worth 17.7 Kb would load faster, and save internet data than a 3500×2321 image worth 2.4 Mb.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F50cidm4pctg5zwcme8ai.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F50cidm4pctg5zwcme8ai.png" alt="The left car is probably looking horrible on your screen, because it’s too blurry" width="800" height="315"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Therefore, smaller images should be used on smaller screens where possible. So, we should somehow switch image sources to adapt the image to the current user’s screen.&lt;/p&gt;

&lt;p&gt;Here’s a &lt;a href="https://image-set-by-timonwa.netlify.app/resolution-switching.html" rel="noopener noreferrer"&gt;live example&lt;/a&gt; and its &lt;a href="https://github.com/Timonwa/image-set-function/blob/main/resolution-switching.html" rel="noopener noreferrer"&gt;source code&lt;/a&gt;. Feel free to view and play with them for a more practical understanding of resolution switching. Continue reading to understand how this demo works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Art direction
&lt;/h2&gt;

&lt;p&gt;We know different images are displayed differently on various screen sizes. However, art direction focuses on the details of the image content shown to the user, not the image resolution. Art direction might not matter for images that don’t pass any information to the user, but it counts for images that give the user information.&lt;/p&gt;

&lt;p&gt;For example, we can have a landscape orientation image with a person standing at the center of the image as the primary focus. We can easily view the person’s face on large screens. However, if we let the image have the same aspect ratio and orientation on smaller screens, we won’t be able to view the person easily,&lt;br&gt;
let alone their face.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1rtpkh7msppbf5jq5mo0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1rtpkh7msppbf5jq5mo0.png" alt="We can easily make the image look fine on any screen" width="800" height="531"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But if we crop the image, thereby changing its aspect ratio and letting it have a portrait orientation, we get to view the person clearly on smaller screens. But when we switch back to larger screens with the new image, it becomes too big.&lt;/p&gt;

&lt;p&gt;Art direction ensures that regardless of the screen size, the user has smooth access to whatever details or content they are supposed to get from an image.&lt;/p&gt;

&lt;p&gt;For a more practical understanding of art direction, you can view the &lt;a href="https://image-set-by-timonwa.netlify.app/art-direction.html" rel="noopener noreferrer"&gt;live example&lt;/a&gt; and play with the &lt;a href="https://github.com/Timonwa/image-set-function/blob/main/art-direction.html" rel="noopener noreferrer"&gt;source code&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Speed up loading of web pages
&lt;/h2&gt;

&lt;p&gt;Nowadays, people tend to access the Internet through their mobile devices, so it is essential to consider this when adding images to your web pages.&lt;/p&gt;

&lt;p&gt;Users should not have to download overly large images for their mobile screens, or wait for larger images to load if they have slow Internet. Instead, you should be able to provide the images suitable for their screen sizes and Internet connection. This customization reduces the time it takes for the web pages to load, the user’s bandwidth and money, and overall improves the user experience of your website.&lt;/p&gt;

&lt;p&gt;So, how to implement all those features?&lt;/p&gt;
&lt;h2&gt;
  
  
  Use image-set function
&lt;/h2&gt;

&lt;p&gt;As I said earlier, the &lt;code&gt;image-set&lt;/code&gt; is a CSS function that allows web developers to turn an image responsive, showing variations of the same image for different screen resolutions when needed.&lt;/p&gt;

&lt;p&gt;The idea is simple. We list a set of images within the &lt;code&gt;image-set&lt;/code&gt; function. The browsers have full access to pick the most appropriate image from this list for different screen resolutions,&lt;br&gt;
with the assurance that the browser would make the best decision about which one to use.&lt;/p&gt;
&lt;h2&gt;
  
  
  How to create responsive images with image-set
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Syntax
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;image-set() = image-set(&amp;lt;image&amp;gt; [&amp;lt;resolution&amp;gt;] [&amp;lt;type&amp;gt;])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;&amp;lt;image&amp;gt;&lt;/code&gt; represents the URL to where the image is stored. It is required.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;resolution&amp;gt;&lt;/code&gt; represents resolution units, &lt;code&gt;x&lt;/code&gt; or &lt;code&gt;dppx&lt;/code&gt;, for dots per pixel unit, &lt;code&gt;dpi&lt;/code&gt;, for dots per inch, and &lt;code&gt;dpcm&lt;/code&gt; for dots per centimeter. Every image within an &lt;code&gt;image-set&lt;/code&gt; must have a unique resolution. The parameter itself is optional, because it’s possible to omit it for the one “default” image of the set.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;type&amp;gt;&lt;/code&gt; specifies the image’s file format — JPEG, PNG, GIF, AVIF, etc. It is optional.&lt;/p&gt;
&lt;h3&gt;
  
  
  Example 1
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.picture&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;image-set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sx"&gt;url('small-car.jpg')&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sx"&gt;url('large-car.jpg')&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In Example 1 &lt;code&gt;1x&lt;/code&gt; identifies the image the browser should use if the image resolution is higher or matches the screen, making the pixel density equal to 1. If the image resolution is lower than the screen’s, the &lt;code&gt;2x&lt;/code&gt; image should be used. You can add more if you want to.&lt;/p&gt;

&lt;p&gt;Don’t forget to check &lt;a href="https://caniuse.com/css-image-set" rel="noopener noreferrer"&gt;current browser support&lt;/a&gt; to add vendor prefixes if your project needs them. Also, a fallback can be added, so browsers not supporting &lt;code&gt;image-set&lt;/code&gt; can have an image to show. We add the fallback before the background-image property with the &lt;code&gt;image-set&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.picture&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url('small-car.jpg')&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c"&gt;/* fallback */&lt;/span&gt;
  &lt;span class="nl"&gt;background-image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;image-set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="sx"&gt;url('small-car.jpg')&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="sx"&gt;url('large-car.jpg')&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="n"&gt;x&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;h3&gt;
  
  
  Example 2
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.picture&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;image-set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sx"&gt;url('car.avif')&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;'image/avif'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="sx"&gt;url('car.jpg')&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;'image/jpeg'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Example 2, we have specified two format types for the same image; &lt;a href="https://avif.io/blog/tutorials/uploadcare/" rel="noopener noreferrer"&gt;AVIF&lt;/a&gt; and JPEG. The widely supported format should always come last, in this case, the JPEG, while the newer formats should go before it.&lt;/p&gt;

&lt;p&gt;The browser will download only one image. The browser checks the first image specified and uses this image if it supports this one. If the browser doesn’t, it ignores the image and moves on to the next.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example 3
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.div&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;image-set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sx"&gt;url('small-car.avif')&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;'image/avif'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sx"&gt;url('large-car.avif')&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;'image/avif'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sx"&gt;url('small-car.jpg')&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;'image/jpeg'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sx"&gt;url('large-car.jpg')&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;'image/jpeg'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Example 3, we specify the resolution along with the image format. This gives the browser even more variations on which image to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does the image-set function differ from the srcset attribute?
&lt;/h2&gt;

&lt;p&gt;Although the &lt;code&gt;image-set&lt;/code&gt; function, and the &lt;code&gt;srcset&lt;/code&gt; attribute set out to do the same thing, there are a few differences between them.&lt;/p&gt;

&lt;p&gt;Obviously, the significant difference is that &lt;code&gt;image-set&lt;/code&gt; function can be used only in CSS, while &lt;code&gt;srcset&lt;/code&gt; attribute can be used only in HTML.&lt;/p&gt;

&lt;p&gt;Another difference, is that unlike with the &lt;code&gt;srcset&lt;/code&gt; attribute, where you can also give image options based on the width of the browser (when art direction is required), you cannot do that with the &lt;code&gt;image-set&lt;/code&gt;. However, art direction can still be achieved in CSS using media queries!&lt;/p&gt;

&lt;p&gt;View the &lt;a href="https://image-set-by-timonwa.netlify.app/responsive-images.html" rel="noopener noreferrer"&gt;live example&lt;/a&gt; on responsive images using the resolution switching method, and the art direction method and play with the &lt;a href="https://github.com/Timonwa/image-set-function/blob/main/responsive-images.html" rel="noopener noreferrer"&gt;source code&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;Responsive images are vital in creating a good user experience, and building faster web pages. Now, you better understand what a responsive image should be, and how we can make better-performance images with the &lt;code&gt;image-set&lt;/code&gt; CSS function.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally &lt;a href="https://uploadcare.com/blog/image-set-for-responsive-images/" rel="noopener noreferrer"&gt;published&lt;/a&gt; by Pelumi Akintokun in Uploadcare Blog&lt;/em&gt;&lt;/p&gt;

</description>
      <category>gratitude</category>
      <category>discuss</category>
    </item>
    <item>
      <title>ECMAScript modules. Going beyond the ordinary</title>
      <dc:creator>Uploadcare</dc:creator>
      <pubDate>Tue, 22 Nov 2022 16:35:13 +0000</pubDate>
      <link>https://forem.com/uploadcare/ecmascript-modules-going-beyond-the-ordinary-4egd</link>
      <guid>https://forem.com/uploadcare/ecmascript-modules-going-beyond-the-ordinary-4egd</guid>
      <description>&lt;p&gt;Let’s say you’re working on a static site generator, and while implementing new features you decide to import text files (HTML, MD, CSS, SVG, etc) as dependencies into JavaScript files. Sure, you may use a bundler with some loader, but what if your bushidō mandates you not to type npm install something every time you have to solve a problem? Well, there is a solution.&lt;/p&gt;

&lt;p&gt;But first, make sure that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You know &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules"&gt;what ESM is about&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;You have Node.js installed, and this Node.js is not outdated.&lt;/li&gt;
&lt;li&gt;You’re not using .mjs as a file extension for your JavaScript code, browsers do not like them, even though the syntax of the files are the same as .js. However, it’s important only if you want to write isomorphic code.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, let’s continue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exercise one. Node.js. Custom loader
&lt;/h2&gt;

&lt;p&gt;Create a loader:&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;// loader.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;readFile&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs/promises&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;isAllowedURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.html&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;.htm&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;.md&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;.css&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;.svg&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;.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;endsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;defaultLoad&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isAllowedURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;defaultLoad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;defaultLoad&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;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;readFile&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;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;))).&lt;/span&gt;&lt;span class="nx"&gt;toString&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;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;endsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`export default &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;shortCircuit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create a file where you want to import some non-JS stuff:&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;// app.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./doc.md&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;css&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./styles.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;svg&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./image.svg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./data.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;css&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;svg&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, boom:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;node &lt;span class="nt"&gt;--loader&lt;/span&gt; ./loader.js ./app.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Huh?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { URL } from 'url';
^^^^^^

SyntaxError: Cannot use import statement outside a module
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Oh, yeah, don’t forget to set &lt;code&gt;"type": "module"&lt;/code&gt; in the package.json of your project — otherwise imports don’t work.&lt;/p&gt;

&lt;p&gt;But with this small key in the package.json everything just works, without the need for additional packages, bundlers, etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SX2yKxMH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/klridmy2vztbh1ak6zks.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SX2yKxMH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/klridmy2vztbh1ak6zks.png" alt="Terminal window where JavaScript file is executed by node. Output is the content of imported HTML, Markdown, CSS, SVG and JSON files" width="880" height="518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you see on the screenshot, you may get this warning:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(node:22662) ExperimentalWarning:
Custom ESM Loaders is an experimental feature.
This feature could change at any time
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s because the feature is &lt;a href="https://nodejs.org/api/esm.html#loaders"&gt;still experimental&lt;/a&gt;, but, well, it works.&lt;/p&gt;

&lt;p&gt;If you want to read more about plans of Node.js team related to loaders, check &lt;a href="https://github.com/nodejs/modules/issues/351"&gt;nodejs/modules#351 issue&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exercise two. Browser. Request interception
&lt;/h2&gt;

&lt;p&gt;Now move to a browser. The task remains the same. We want to load modules, but not JS modules, rather we want static files with styles, templates and plain text. Browsers do not support special “hooks” for ES Modules. What’s the plan?&lt;/p&gt;

&lt;p&gt;Well, let’s create a dragnet using &lt;a href="https://uploadcare.com/blog/service-workers-tutorial/"&gt;Service Workers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The tools are different, but the approach is the same.&lt;/p&gt;

&lt;p&gt;Create a Service Worker file:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;isAllowedURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.html&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;.htm&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;.md&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;.css&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;.svg&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;.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;endsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;handleRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&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;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;text&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;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;endsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`export default &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/javascript&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destination&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;isAllowedURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;respondWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handleRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Register it somewhere on an HTML page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- index.html --&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./sw.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use the same imports as in the Node.js example above:&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;// module.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./doc.md&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;css&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./styles.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;svg&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./image.svg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./data.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;css&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;svg&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But this time, instead of marking package.json as a “module,” do the same on the script tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- index.html --&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./module.js"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now serve the page, open DevTools and check the logging:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IQFwzeYB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gtjuqoi727mjf4odqbyw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IQFwzeYB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gtjuqoi727mjf4odqbyw.png" alt="DevTools with the logged content of imported HTML, Markdown, CSS, SVG and JSON files" width="880" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No bundlers, no additional stuff. Just pure JavaScript and browser API. Cool, isn’t it?&lt;/p&gt;

&lt;p&gt;If you decide to use this solution in a real project, read Service Worker’s docs carefully. There are some important limitations and nuances of compatibility with different web browsers. For instance, currently Firefox does not run Service Workers in private browsing mode. This is &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1320796"&gt;by design&lt;/a&gt;, but probably &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1320796"&gt;will be changed&lt;/a&gt; in the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exercise three. Node.js + Browser. Request parameters
&lt;/h2&gt;

&lt;p&gt;Okay, now it’s time for sick stuff. It’s just an experiment and I don’t encourage you to try it, but why not try when you can?&lt;/p&gt;

&lt;p&gt;If you don’t know, ES Modules support top level await. It means that before a module “returns” its export, you can do something asynchronous in it. For instance, make a network call and get a response. Where does this lead us? Right.&lt;/p&gt;

&lt;p&gt;Create a loader module:&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;// load.js&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Import everything else using this module as a proxy:&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;// module.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./load.js?./index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./load.js?./doc.md&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;css&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./load.js?./styles.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;svg&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./load.js?./image.svg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./load.js?./data.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;css&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;svg&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even though the example is simplified, it’s already isomorphic. Which means you can use the code above in a browser and in Node.js without any changes. Try it.&lt;/p&gt;

&lt;p&gt;I don’t think that anyone will seriously use this method to load modules, but the approach itself is at least interesting to think about.&lt;/p&gt;

&lt;p&gt;An important thing to note here is that each module’s exports are cached. The cache is based on the module’s URI. Therefore, if the imported files are changed dynamically, their URIs should be changed too. That means that it’s possible to use &lt;a href="https://javascript.info/modules-dynamic-imports"&gt;dynamic imports&lt;/a&gt; only in this kind of situation. But when we have a top level await support, it’s not a huge problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion. Kind of
&lt;/h2&gt;

&lt;p&gt;You may ask, “Is there any value in this at all? It’s easier to use &lt;code&gt;fs.readFile&lt;/code&gt; or &lt;code&gt;fetch&lt;/code&gt; instead of importing a module!”&lt;/p&gt;

&lt;p&gt;I would like not to answer. You never know when the weird knowledge you have will help you in the future.&lt;/p&gt;

&lt;p&gt;Anyway, I hope it was a fun ride! Maybe you’ve learned something new and useful.&lt;/p&gt;

&lt;p&gt;Use more ESM and less CJS. Peace!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally &lt;a href="https://uploadcare.com/blog/ecmascript-modules-going-beyond/"&gt;published&lt;/a&gt; by Sergey Matiyasevich in Uploadcare Blog&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>A guide to Intersection Observer</title>
      <dc:creator>Uploadcare</dc:creator>
      <pubDate>Mon, 21 Nov 2022 19:06:27 +0000</pubDate>
      <link>https://forem.com/uploadcare/a-guide-to-intersection-observer-517p</link>
      <guid>https://forem.com/uploadcare/a-guide-to-intersection-observer-517p</guid>
      <description>&lt;p&gt;At some point during your frontend career, you probably had to or wanted to, figure out where an element is related to the scrolling position of the user. If not, don’t worry, I believe this will still be interesting to you, because it might pop some ideas and give you inspiration for your projects. Today, we will go through the Intersection Observer API — an easy way to determine whether the DOM element somehow intersects with the viewport, or another element.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Intersection Observer?
&lt;/h2&gt;

&lt;p&gt;Throughout the frontend history, detecting when something is intersecting with another thing was tricky. Often, hand-crafted solutions were unreliable, to the point it caused some visible impact on users’ browsers and websites. Today, we are lucky to have the Intersection Observer API, but why? What were the main drivers behind this development? Let’s look at some examples of how things were done before.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://uploadcare.com/blog/lazy-loading-images/"&gt;lazy loading technique&lt;/a&gt; is one example of where developers want to know when a DOM element is entering the viewport. To lazy load an image, you have to know whether a user is relatively close to the image position on the page as they are scrolling. You could achieve this by hooking up the scroll event, and calling &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect"&gt;&lt;code&gt;getBoundingClientRect&lt;/code&gt; method&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;getBoundingClientRect&lt;/code&gt; would return an object providing information about the size of an element and its position relative to the viewport. Then, you could figure out whether to trigger the download of the image your user wants to see. Or, you could trigger a request to notify that the user just viewed an image or specific element on the page.&lt;/p&gt;

&lt;p&gt;This solution was used over and over in the past. However, this solution was often sluggish because calling &lt;code&gt;getBoundingClientRect&lt;/code&gt; forces a reflow of the page. The reflow is a process when the browser needs to re-calculate the position, and dimensions of the elements on the page. If called often, browsers and computers can only take so much heat, and will eventually start to become laggy.&lt;/p&gt;

&lt;p&gt;Here’s a small Codepen example of how you can tap into the scroll listener and get the data about the desired element:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/nikolalsvk/embed/WNzpJZz?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;For this exact reason, the Intersection Observer API was introduced in Chrome 51. What makes this API better than the approach with the &lt;code&gt;getBoundingClientRect&lt;/code&gt;, is that it provides a way to asynchronously observe changes in the intersection of a target element with another element. That way, when you use Intersection Observer, you’re not stressing the browser and the page, as much as you are with the &lt;code&gt;getBoundingClientRect&lt;/code&gt; approach.&lt;/p&gt;

&lt;p&gt;Awesome, now that we went through the backstory of how Intersection Observer came to be, let’s dive in and see how we can use it properly.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use the Intersection Observer?
&lt;/h2&gt;

&lt;p&gt;To get the best idea of how to use an intersection observer, let’s dive right into how to call it in code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;some-id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;rootMargin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.0&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;observer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;IntersectionObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The IntersectionObserver constructor receives two arguments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;callback&lt;/code&gt; — a callback function that gets called whenever a threshold is crossed in any direction.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;options&lt;/code&gt; — an object with additional configuration.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;options&lt;/code&gt; object contains following fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;root&lt;/code&gt; — it pinpoints an element that serves as a viewport, and must be an ancestor of the target element (we will show later how to target an element). If you leave this option out, the observer will default to the browser viewport.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;rootMargin&lt;/code&gt; — it tells the observer when to trigger the intersection between the root and the target element. Here, you can put values like you usually do for a margin in CSS.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;threshold&lt;/code&gt; — this can be a single number, or array of numbers. The threshold indicates at what percentage of the target element’s visibility you want the provided callback to get called. So, if you want to lazy load an image only when a user scrolls 25% of it, then you can put the value of &lt;code&gt;0.25&lt;/code&gt; there. If you want some logic to be triggered, both at 25% and 50% of visibility of the target, then you put &lt;code&gt;[0.25, 0.5]&lt;/code&gt; array here.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cool, now we know what the constructor receives, but how do we actually target an element to be observed? Let’s find out through an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;target-element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nice, now when our element with the ID &lt;code&gt;target-element&lt;/code&gt; intersects with the root element we set, the callback will get called. Naturally, we should look into how to write a proper callback for the Intersection Observer:&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;intersectionCallback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// you can find out easily if target is intersecting by inspecting `isIntersecting` property&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isIntersecting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Hey, I'm intersecting`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The callback receives a list of entries that are of &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry"&gt;&lt;code&gt;IntersectionObserverEntry&lt;/code&gt;&lt;/a&gt; type. Having a list as the first argument means that one observer can observe multiple target elements. Each entry has a set of fields, but one that’s most often used is the &lt;code&gt;isIntersecting&lt;/code&gt;. In the example above, we log to the browser console whenever our target is intersected.&lt;/p&gt;

&lt;p&gt;The second argument passed to the callback is the observer itself. This can be useful when you want to stop observing the target after an intersection — then you call &lt;code&gt;observer.unobserve()&lt;/code&gt; in the callback.&lt;/p&gt;

&lt;p&gt;Great, now that we went through some basics on using the Intersection Observer, let’s put it to use and build something.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Intersection Observer
&lt;/h2&gt;

&lt;p&gt;Let’s build a working example where a video starts playing as you scroll into it, and it pauses as you scroll away. To achieve this, we’ll use the powerful Intersection Observer we just showcased in the section above.&lt;/p&gt;

&lt;p&gt;To start off, we’ll need a video inside HTML. I will share the important HTML, and full JS code if you want to try it out. There will also be an interactive demo you can try out at the bottom. Here’s the simplified HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;video&lt;/span&gt; &lt;span class="na"&gt;muted&lt;/span&gt; &lt;span class="na"&gt;controls&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt;
    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://ucarecdn.com/33fa1b5d-a164-4178-908c-5a51f872fcef/video.webm"&lt;/span&gt;
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"video/webm"&lt;/span&gt;
  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt;
    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://ucarecdn.com/1b63a65c-7796-4b23-a6fc-bb751f1221ed/video.ogg"&lt;/span&gt;
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"video/ogg"&lt;/span&gt;
  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt;
    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://ucarecdn.com/ec3f39c9-be9f-4231-a4db-d7fcbd209e71/video.mp4"&lt;/span&gt;
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"video/mp4"&lt;/span&gt;
  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/video&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the HTML we simply put a &lt;code&gt;video&lt;/code&gt; tag with several sources. And, finally, our Intersection Observer code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;video&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;video&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;IntersectionObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;intersectionRatio&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;paused&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pause&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;play&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we are getting the video element using &lt;code&gt;document.querySelector('video')&lt;/code&gt;. Then, we define our Intersection Observer instance with a callback and a threshold of &lt;code&gt;1&lt;/code&gt;. The threshold of &lt;code&gt;1&lt;/code&gt; means that our callback will trigger when the video is fully visible, or it stops being fully visible.&lt;/p&gt;

&lt;p&gt;In our callback, we check whether the video is not fully visible, with the &lt;code&gt;entry.intersectionRatio !== 1&lt;/code&gt; check. The &lt;code&gt;intersectionRatio&lt;/code&gt; indicates which portion of the element is visible, and it goes from 0 to 1 — where 1 means it is fully visible. Everything between 0 and 0.99 means that the element, video element in our case, is hidden a bit. There, we also check whether the video is paused. If the video is playing and it is hidden a bit — we pause it.&lt;/p&gt;

&lt;p&gt;Now, if the video’s &lt;code&gt;intersectionRatio&lt;/code&gt; is 1, we fall into the else branch and we play the video.&lt;/p&gt;

&lt;p&gt;This is a cool trick you can try out on your project. It doesn’t require a lot of code, and can be a good user experience. But remember to not autoplay videos by default — it can be annoying to users. Here’s a demo you can play around with:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/nikolalsvk/embed/NWYgMJa?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Summing up
&lt;/h2&gt;

&lt;p&gt;I hope you had a great time reading, and trying out the Intersection Observer API. If you learned a thing or two, then I call this blog post a success. Let’s go over the things we learned today:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Intersection Observer can be used to detect intersections between elements, or between an element and the viewport.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You use the API by instantiating the observer with &lt;code&gt;new IntersectionObserver(callback, options)&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;callback&lt;/code&gt; parameter is a method that receives an array of entries, and the observer itself.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;options&lt;/code&gt; parameter is an object that can consist of &lt;code&gt;root&lt;/code&gt;, &lt;code&gt;rootMargin&lt;/code&gt;, and &lt;code&gt;threshold&lt;/code&gt; properties. This parameter is optional.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The instantiated observer can observe an element you pass to it with &lt;code&gt;observer.observe(element)&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That’s it! You’ve learned the basics. If you’re looking for something more advanced, you can always play around with the threshold option that Intersection Observer receives. Or, you can dabble with the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry"&gt;IntersectionObserverEntry&lt;/a&gt; object for extra information when the intersection happens. If we tried to cover that, this blog post would be a lengthy one, so we will save it for another time.&lt;/p&gt;

&lt;p&gt;Until then, thanks for reading, and catch you in the next one.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally &lt;a href="https://uploadcare.com/blog/intersection-observer-guide/"&gt;published&lt;/a&gt; by Nikola Đuza in Uploadcare Blog&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>Different Types of Video File Formats and Why WebM and MP4 Beat Them All</title>
      <dc:creator>Uploadcare</dc:creator>
      <pubDate>Tue, 19 Apr 2022 05:00:10 +0000</pubDate>
      <link>https://forem.com/uploadcare/different-types-of-video-file-formats-and-why-webm-and-mp4-beat-them-all-3o0f</link>
      <guid>https://forem.com/uploadcare/different-types-of-video-file-formats-and-why-webm-and-mp4-beat-them-all-3o0f</guid>
      <description>&lt;p&gt;Which video formats are the best in terms of size/quality and are compatible with most players on the web, Android &amp;amp; iOS? The short answer for 2021 is: WebM backed up by MP4 is the winning stack to consider. Glance through this article for all the why's and get some encoding automation options.&lt;/p&gt;

&lt;p&gt;💡 This content will be helpful for developers who are working on video sharing apps, CMSs, and ecommerce platforms. We didn’t cover the part about streaming in much detail, but ping us in the comments if you’re interested.&lt;/p&gt;

&lt;h2&gt;
  
  
  Video File Formats, Codecs, and Containers: What’s the Difference?
&lt;/h2&gt;

&lt;p&gt;You’ve probably come across such acronyms as AVI, MPEG-4, WMV, DivX, WebM, or MP4. For non-savvy users, they stand for different types of video files. But the truth is, some of them are indeed file formats defined by their &lt;em&gt;multimedia containers,&lt;/em&gt; and others are &lt;em&gt;codecs&lt;/em&gt; that help to shrink video and audio data inside those containers.&lt;/p&gt;

&lt;p&gt;There are three main reasons to start differentiating formats, codecs, and containers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Video file formats and extensions don’t tell much about file characteristics. Containers and codecs do.&lt;/li&gt;
&lt;li&gt;Containers and codecs define whether a file will be played on a particular device.&lt;/li&gt;
&lt;li&gt;Containers and codecs influence how the data is stored and compressed, hence have a direct impact on video size and quality.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s look at video file formats, containers and codecs from a developer’s perspective and distill their main characteristics.&lt;/p&gt;

&lt;h3&gt;
  
  
  What’s a multimedia container?
&lt;/h3&gt;

&lt;p&gt;The word &lt;em&gt;container&lt;/em&gt; speaks for itself. It’s like a bucket that may contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Encoded video and audio tracks (can be several in different languages)&lt;/li&gt;
&lt;li&gt;Subs and interactivity elements like chapters and menus&lt;/li&gt;
&lt;li&gt;Synchronization information to make it all play together&lt;/li&gt;
&lt;li&gt;Metadata for SEO purposes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GPlVCNi3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p5udugu59l48qg8eusgl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GPlVCNi3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p5udugu59l48qg8eusgl.png" alt="Image description" width="880" height="492"&gt;&lt;/a&gt;&lt;br&gt;
'Video containers are also called video wrappers and can store various types of data.'&lt;/p&gt;

&lt;p&gt;Each multimedia container stores different types of data and is compatible with particular codecs and players. Here is an overview of the containers you’ve probably heard about:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
    &lt;thead&gt;
    &lt;tr&gt;
        &lt;th&gt;&lt;strong&gt;Container&lt;/strong&gt;&lt;/th&gt;
        &lt;th&gt;&lt;strong&gt;Video file extensions&lt;/strong&gt;&lt;/th&gt;
        &lt;th&gt;&lt;strong&gt;Perks&lt;/strong&gt;&lt;/th&gt;
        &lt;th&gt;&lt;strong&gt;Limitations&lt;/strong&gt;&lt;/th&gt;
        &lt;th&gt;&lt;strong&gt;Quality and compression&lt;/strong&gt;&lt;/th&gt;
        &lt;th&gt;&lt;strong&gt;Best for&lt;/strong&gt;&lt;/th&gt;
    &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
    &lt;tr&gt;
        &lt;td&gt;Audio Video Interleave, AVI&lt;/td&gt;
        &lt;td&gt;.avi&lt;/td&gt;
        &lt;td&gt;
            &lt;ul&gt;
                &lt;li&gt;Supports many different codecs, can run both on Mac and Windows
&lt;/li&gt;
                &lt;li&gt;High quality of video&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/td&gt;
        &lt;td&gt;
            &lt;ul&gt;
                &lt;li&gt;No video chapters or interactive menus
&lt;/li&gt;
                &lt;li&gt;Doesn’t support some modern compression techniques&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/td&gt;
        &lt;td&gt;Low degree of compression and relatively large file sizes with possible quality losses&lt;/td&gt;
        &lt;td&gt;DVD&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;MPEG-4 Part 14, MP4&lt;/td&gt;
        &lt;td&gt;.mp4&lt;/td&gt;
        &lt;td&gt;
            &lt;ul&gt;
                &lt;li&gt;Browser compatible
&lt;/li&gt;
                &lt;li&gt;Was designed for low bit rates and is bandwidth friendly
&lt;/li&gt;
                &lt;li&gt;Supports chapters and interactivity&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/td&gt;
        &lt;td&gt;
            &lt;ul&gt;
                &lt;li&gt;Relatively high loading time
&lt;/li&gt;
                &lt;li&gt;Losses of video and audio quality after compression
&lt;/li&gt;
                &lt;li&gt;Codec dependent
&lt;/li&gt;
                Non loyalty-free
            &lt;/ul&gt;
        &lt;/td&gt;
        &lt;td&gt;High degree of compression and smaller file sizes&lt;/td&gt;
        &lt;td&gt;Web, mobile, social media, streaming&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Matroska&lt;/td&gt;
        &lt;td&gt;.mkv&lt;br&gt;.mk3d&lt;br&gt;&lt;br&gt;
&lt;/td&gt;
        &lt;td&gt;
            &lt;ul&gt;
                &lt;li&gt;Supports all codecs
&lt;/li&gt;
                &lt;li&gt;Open-source and loyalty free&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/td&gt;
        &lt;td&gt;Is not natively supported on mobile devices&lt;/td&gt;
        &lt;td&gt;Different levels of lossy and lossless compression&lt;/td&gt;
        &lt;td&gt;DVD, Web&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Ogg&lt;/td&gt;
        &lt;td&gt;.ogg&lt;br&gt;.ogv&lt;br&gt;.ogx&lt;/td&gt;
        &lt;td&gt;
            &lt;ul&gt;
                &lt;li&gt;Open-source and free
&lt;/li&gt;
                &lt;li&gt;Is designed to provide efficient video streaming&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/td&gt;
        &lt;td&gt;
            &lt;ul&gt;
                &lt;li&gt;Not supported by Safari and Internet Explorer
&lt;/li&gt;
                &lt;li&gt;Codec dependent&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/td&gt;
        &lt;td&gt;Lossy and lossless compression, relatively small file size&lt;/td&gt;
        &lt;td&gt;Streaming&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;QuickTime File Format&lt;/td&gt;
        &lt;td&gt;.mov&lt;br&gt;.qt&lt;/td&gt;
        &lt;td&gt;Good for video editing (does it in place, without rewriting the data)&lt;/td&gt;
        &lt;td&gt;Is supported by QuickTime Player and just a few other players&lt;/td&gt;
        &lt;td&gt;High quality with substantial file sizes&lt;/td&gt;
        &lt;td&gt;Apple devices&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Flash Video, FLV&lt;/td&gt;
        &lt;td&gt;.flv&lt;/td&gt;
        &lt;td&gt;Supports all types of interactive content&lt;/td&gt;
        &lt;td&gt;
            &lt;ul&gt;
                &lt;li&gt;No chapters or interactive elements
&lt;/li&gt;
                &lt;li&gt;Not supported by iOS or web
&lt;/li&gt;
                &lt;li&gt;High video making cost&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/td&gt;
        &lt;td&gt;No severe loss of quality, relatively big file sizes&lt;/td&gt;
        &lt;td&gt;Web, Interactive content&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;WebM&lt;/td&gt;
        &lt;td&gt;.webm&lt;/td&gt;
        &lt;td&gt;
            &lt;ul&gt;
                &lt;li&gt;Open source and loyalty free
&lt;/li&gt;
                &lt;li&gt;Based on Matroska container profile and supports most codecs
&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/td&gt;
        &lt;td&gt;
            &lt;ul&gt;
                &lt;li&gt;Relatively low video quality
&lt;/li&gt;
                &lt;li&gt;No support for some browsers and devices
&lt;/li&gt;
                &lt;li&gt;No interactive elements&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/td&gt;
        &lt;td&gt;High video quality with relatively small file sizes&lt;/td&gt;
        &lt;td&gt;Web&lt;/td&gt;
    &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  What’s a codec?
&lt;/h3&gt;

&lt;p&gt;Codecs compress (en*&lt;em&gt;co&lt;/em&gt;&lt;em&gt;de) or decompress (&lt;/em&gt;&lt;em&gt;dec&lt;/em&gt;*ode) video and audio files. As video data is always massive, codecs shrink it to make storage and delivery easier.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://elements.envato.com/lp/create/video-templates/"&gt;Video content&lt;/a&gt; is booming these days, so it’s hard to underestimate the role of codecs: thanks to encoding and decoding, anyone can create or watch videos all around the globe.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Imagine that all image files have to be put in an archive. You start emailing people your photos inside .zip or .rar files, in accordance with this new law. Although both WinZip and WinRar have different features, at the end of the day, it's either a JPEG, PNG, GIF or BMP inside that file and that's what really makes the image. You'd say "The codec is JPEG, in a ZIP container.“&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;– a simple explanation by a Reddit user.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;👉 &lt;a href="https://dev.to/image-file-types/"&gt;Learn about the Most Common Image File Extensions&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What codecs actually do is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compress a video file and make it fit the multimedia container format&lt;/li&gt;
&lt;li&gt;Decompress the file and make it ready to play if the destination device supports the codec&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DRFHqv33--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zilqx4ffff8xa59posq5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DRFHqv33--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zilqx4ffff8xa59posq5.png" alt="Image description" width="880" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a list of popular codecs with supported multimedia container formats.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
    &lt;tbody&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;strong&gt;Some popular video codecs&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;Highlights&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;
&lt;strong&gt;Supported container formats&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;Best for&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;H.264/AVC&lt;/td&gt;
        &lt;td&gt;The most commonly used nowadays, supports video streaming and is also used on cable broadcasting.&lt;/td&gt;
        &lt;td&gt;MP4&lt;br&gt;MOV&lt;br&gt;F4V&lt;br&gt;3GP&lt;br&gt;TS&lt;br&gt;&lt;br&gt;
&lt;/td&gt;
        &lt;td rowspan="2"&gt;Online HD videos and streaming. H.265 is the best in terms of video quality. H.264 is better for
            streaming thanks to high compatibility.
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;H.265/HEVC&lt;/td&gt;
        &lt;td&gt;Offers 50% better compression than H.264/AVC. Supports 8K resolution.&lt;/td&gt;
        &lt;td&gt;TS&lt;br&gt;MP4&lt;br&gt;3GP&lt;br&gt;MKV&lt;br&gt;&lt;br&gt;
&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;AV1&lt;/td&gt;
        &lt;td&gt;Open-source and loyalty-free codec, competing with H.265.&lt;/td&gt;
        &lt;td&gt;MP4&lt;br&gt;3GP&lt;br&gt;MKV&lt;br&gt;&lt;br&gt;
&lt;/td&gt;
        &lt;td&gt;Those who need H.264 and H.265 for free.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;VP9&lt;/td&gt;
        &lt;td&gt;A free codec developed by Google. Supported by Android, Chrome, and YouTube but not supported by Apple.&lt;/td&gt;
        &lt;td&gt;WEBM&lt;br&gt;MKV&lt;br&gt;&lt;br&gt;
&lt;/td&gt;
        &lt;td&gt;Audiences on Google, Android, or YouTube.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;MPEG-4 and DivX are legacy codecs that can still be seen nowadays but are outshined by their widespread competitors, H.264 and H.265. They already lag behind them in terms of efficiency and mobile delivery.&lt;/p&gt;

&lt;p&gt;💡 Codecs and containers are frequently confused. I bet you can’t tell the difference between MPEG-4 and MP4 even after reading the paragraphs above. Cheat sheet: MPEG is a compression method, and MPEG-4 is one of its versions which is designed for low bandwidth audio/video encoding. MP4, abbreviated from MPEG-4 Part 14, is a media container.&lt;/p&gt;

&lt;p&gt;If you see an .mp4 file, it doesn’t mean it was encoded with the MPEG-4 codec. As the MP4 container is compatible with a number of popular codecs, it can be any of them. On the other hand, videos encoded in MPEG-4 can be a part of any supported container like Matroska or Ogg.&lt;/p&gt;

&lt;h3&gt;
  
  
  What’s a video file format?
&lt;/h3&gt;

&lt;p&gt;A video file format is one that stores digital video data. As we already know, the way the data is stored is defined by the multimedia container; that’s why video file formats and extensions are usually named after them, causing lots of confusion.&lt;/p&gt;

&lt;p&gt;Here’s a list of the most used video file formats with their corresponding containers, codecs, and file extensions.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
    &lt;tbody&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;strong&gt;Video file format&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;Video filename extension&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;
&lt;strong&gt;Multimedia container&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;Video codec&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Matroska&lt;/td&gt;
        &lt;td&gt;.mkv&lt;/td&gt;
        &lt;td&gt;Matroska&lt;/td&gt;
        &lt;td&gt;any&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Ogg Video&lt;/td&gt;
        &lt;td&gt;.ogv&lt;br&gt;.ogg&lt;br&gt;
&lt;/td&gt;
        &lt;td&gt;Ogg&lt;/td&gt;
        &lt;td&gt;Theora, Dirac&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;WebM&lt;/td&gt;
        &lt;td&gt;.webm&lt;/td&gt;
        &lt;td&gt;WebM based on Matroska&lt;/td&gt;
        &lt;td&gt;VP8, VP9, AV1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;MP4&lt;/td&gt;
        &lt;td&gt;.mp4&lt;br&gt;.m4p (with DRM)&lt;br&gt;.m4v&lt;/td&gt;
        &lt;td&gt;MPEG-4 Part 14 (MP4)&lt;/td&gt;
        &lt;td&gt;H.265, H.264, MPEG-4 Part 2, MPEG-2, MPEG-1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;And here is how it looks in the real world:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MMEc45Im--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sn46602gh5kuvu1zfwaj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MMEc45Im--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sn46602gh5kuvu1zfwaj.png" alt="Image description" width="880" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Pick Video File Formats and Why WebM and MP4 Are Worth Considering
&lt;/h2&gt;

&lt;p&gt;When choosing from different types of video file formats, there are four things you should think about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What kind of players and devices should the video be compatible with?&lt;/li&gt;
&lt;li&gt;Does the size matter, and how much video data are you ready to store?&lt;/li&gt;
&lt;li&gt;What level of video playback quality do you expect?&lt;/li&gt;
&lt;li&gt;Will you need the video to be livestreamed?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you need a video file format that’s compatible with most devices, platforms, and browsers, including low bandwidth cases, look at MP4. It provides the best balance between quality and size, is compatible with several of the most popular codecs, and is widely supported.&lt;/p&gt;

&lt;p&gt;💡 To further improve web performance, encode MP4 videos to WebM and use them together. WebM files are smaller in size and are the best fit for most web browsers. Force WebM every time a browser supports it, and if not, fall back to MP4. This can be done via video source tags. &lt;a href="https://web.dev/video-and-source-tags/"&gt;Check out this setup guide from Google&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Video File Processing, Reformatting and Automation
&lt;/h2&gt;

&lt;p&gt;To prepare your video files for the web or mobile apps, convert them to the formats you chose. The best practice is to use FFmpeg. It’s a free and open-source tool designed for command-line-based video and audio file processing. It can easily &lt;a href="https://web.dev/containers-and-codecs/"&gt;convert your files to WebM and MP4 containers&lt;/a&gt; and even allows you to specify codecs.&lt;/p&gt;

&lt;p&gt;Apart from reformatting files and choosing codecs, you might want to process them to fit your website. Such processing can include: cropping, trimming, adjusting resolution, and generating thumbnails.&lt;/p&gt;

&lt;p&gt;All these operations can be performed on autopilot if you adopt Uploadcare, an out-of-the-box infrastructure for file uploads, processing, and delivery. Apart from reformatting files to web-friendly WebM, Ogg, and MP4, &lt;a href="https://uploadcare.com/docs/transformations/video-encoding/"&gt;Uploadcare lets you standardize video assets in terms of size and quality&lt;/a&gt;. In fact, it’s a single robust API that allows you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run URL-based video transformations in the browser&lt;/li&gt;
&lt;li&gt;Set up a background workflow with automated delivery&lt;/li&gt;
&lt;li&gt;Process and standardize user-generated video content&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 &lt;a href="https://uploadcare.com/products/transformations/"&gt;Learn more about image and video transformations with Uploadcare&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Encoding and Handling User-Generated Video Content
&lt;/h2&gt;

&lt;p&gt;Let’s say you’re building a platform for pasta lovers who can share their favourite recipes or host live workshops. Asking users to upload video files of certain types can create friction. On the other hand, delivering files as they are can affect your web performance at low bit rates and grossly inflate traffic costs.&lt;/p&gt;

&lt;p&gt;That’s why the best practice is to receive files as they are and encode them programmatically upon delivery. This can be done by setting up file encoding functionality, but that’s obviously not the best option in terms of time and money. Instead, you can take a buy-don’t-build approach and use a third-party image CDN with video encoding support.&lt;/p&gt;

&lt;p&gt;Uploadcare has a built-in image CDN that takes on all the video handling, including video storage, editing, and reformatting, so you can focus on your core product.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case study:&lt;/strong&gt; Polished is a marketplace that offers job seekers to get video feedback from hiring professionals. The team had to implement video uploading, processing, and delivery to get the service up and running.&lt;/p&gt;

&lt;p&gt;If done in-house, such infrastructure would’ve taken considerable time and resources, so they integrated Uploadcare: an out-of-the-box API-based solution. As a result, they launched the product in just two months and now handle video files up to 400 MB with no sweat.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://uploadcare.com/customers/polished/"&gt;Read the full story&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  So, WebM, MP4, or Ogg? Choose Your Fighter!
&lt;/h2&gt;

&lt;p&gt;Now you know the difference between popular video file formats and what actually makes that difference. Hint: codecs and containers do! Choose your file stack wisely and consider delegating file handling to a trusted provider. Reinventing the wheel when it comes to video may turn out to be a great waste of time and resources.&lt;/p&gt;

</description>
      <category>mp4</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
