<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ayc0</title>
    <description>The latest articles on DEV Community by Ayc0 (@ayc0).</description>
    <link>https://dev.to/ayc0</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%2F202017%2F2247c005-889d-4cd2-8de9-7e8812d2c713.png</url>
      <title>DEV Community: Ayc0</title>
      <link>https://dev.to/ayc0</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ayc0"/>
    <language>en</language>
    <item>
      <title>@blocz/react-responsive v4</title>
      <dc:creator>Ayc0</dc:creator>
      <pubDate>Sat, 04 Jan 2025 10:59:29 +0000</pubDate>
      <link>https://dev.to/ayc0/bloczreact-responsive-v4-2j5i</link>
      <guid>https://dev.to/ayc0/bloczreact-responsive-v4-2j5i</guid>
      <description>&lt;p&gt;&lt;code&gt;@blocz/react-responsive&lt;/code&gt; v4 was just released with a few removals of deprecated APIs. Those are &lt;code&gt;&amp;lt;Match&amp;gt;&lt;/code&gt; and the CSS-in-JS support. You can check out the full release details here: &lt;a href="https://github.com/bloczjs/react-responsive/releases/tag/v4.0.0" rel="noopener noreferrer"&gt;https://github.com/bloczjs/react-responsive/releases/tag/v4.0.0&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Breaking changes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  No more &lt;code&gt;&amp;lt;Match&amp;gt;&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;In the v3, &lt;code&gt;@blocz/react-responsive&lt;/code&gt; exposed a &lt;code&gt;&amp;lt;Match&amp;gt;&lt;/code&gt; component that was reading the props &lt;code&gt;only&lt;/code&gt; and &lt;code&gt;matchMedia&lt;/code&gt; in any of its children. This was inspired from &lt;code&gt;@reach/router&lt;/code&gt; v1’s &lt;code&gt;&amp;lt;Router&amp;gt;&lt;/code&gt; component. It could be used such as (from the previous README.md):&lt;/p&gt;

&lt;blockquote&gt;

&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Match&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@blocz/react-responsive&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Match&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"xs"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;xs&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"sm"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;sm&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"md"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;md&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"sm lg"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;sm and lg&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"xl"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;xl&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"smDown"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;nested smDown&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;matchMedia&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"(min-width:768px) and (max-width:992px),(max-width:576px)"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;(min-width:768px) and (max-width:992px),(max-width:576px)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Match&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;This has 3 major issues:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It requires using &lt;a href="https://react.dev/reference/react/Children" rel="noopener noreferrer"&gt;&lt;code&gt;React.Children&lt;/code&gt;&lt;/a&gt; to manually crawl all the children and wrap each of the ones matching either a &lt;code&gt;only&lt;/code&gt; or &lt;code&gt;matchMedia&lt;/code&gt; prop in a &lt;code&gt;&amp;lt;Only&amp;gt;&lt;/code&gt; component. Problem: this API is considered as legacy in React and they even mention this:
:::caution[Pitfall]
Using Children is uncommon and can lead to fragile code. See common alternatives.
:::&lt;/li&gt;
&lt;li&gt;If any child was a custom component that was using one of those props, you’d get a conflict,&lt;/li&gt;
&lt;li&gt;This is not compatible with TypeScript. The README mentioned a way to make it work with custom components. But for regular HTML elements, we had to hack around. And this hack was injected into all projects depending on &lt;code&gt;@blocz/react-responsive&lt;/code&gt; to all HTML elements those 2 props &lt;code&gt;only&lt;/code&gt; and &lt;code&gt;matchMedia&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Also this wasn’t creating a great DX as it wouldn’t work with spread props, and similar situations.&lt;/p&gt;

&lt;p&gt;So in this v4, we decided to fully drop this API, and instead push for either &lt;code&gt;&amp;lt;Only&amp;gt;&lt;/code&gt; (more declarative than &lt;code&gt;&amp;lt;Match&amp;gt;&lt;/code&gt;), or hooks like &lt;code&gt;useBreakpoint()&lt;/code&gt; (more composable).&lt;/p&gt;

&lt;h3&gt;
  
  
  Removal of CSS-in-JS support
&lt;/h3&gt;

&lt;p&gt;Initially, &lt;code&gt;toJSON&lt;/code&gt; and &lt;code&gt;toCSS&lt;/code&gt; were designed to work in a project using &lt;a href="https://styletron.org/" rel="noopener noreferrer"&gt;&lt;code&gt;styletron&lt;/code&gt;&lt;/a&gt;, and within this project, we wanted to make it possible to plug styletron into &lt;code&gt;@blocz/react-responsive&lt;/code&gt; breakpoints for responsive designs.&lt;/p&gt;

&lt;p&gt;But this was a long time ago, and a lot of things changed since:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We stopped working on this website, so we have less direct incentive to make those 2 coincide,&lt;/li&gt;
&lt;li&gt;In general, CSS-in-JS fell in terms of usages, and more specifically &lt;code&gt;styletron&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;Our support for CSS-in-JS was not great: it could be adapted to a lot of use-cases as &lt;code&gt;toJSON&lt;/code&gt; could work for any nesting of objects, but &lt;code&gt;toCSS&lt;/code&gt; couldn’t and we didn’t want to have to maintain a CSS parser. And in general we didn’t want to keep up with all the new features of either CSS in general or CSS-in-JS engines.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Moreover, this layer of connection between &lt;code&gt;@blocz/react-responsive&lt;/code&gt; and CSS-in-JS can still be replicated using &lt;code&gt;useBreakpoint()&lt;/code&gt; and custom wrapper in user-land.&lt;/p&gt;

&lt;p&gt;All of those reasons lead to the full removal of both &lt;code&gt;toJSON&lt;/code&gt; and &lt;code&gt;toCSS&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other changes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  React 19 support
&lt;/h3&gt;

&lt;p&gt;This v4 officially adds support for React 19. Even if technically it was already compatible and you can use the v3, you may have warnings with your package managers. Also we added tests for React 19.&lt;/p&gt;

&lt;h3&gt;
  
  
  Node version
&lt;/h3&gt;

&lt;p&gt;This shouldn’t impact any users as this is mostly for our internal tooling: we upgraded the supported Node.js version to 20 &amp;amp; 22 (the current LTS), and dropped support for all other versions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bundle size
&lt;/h3&gt;

&lt;p&gt;With the removal of &lt;code&gt;toJSON&lt;/code&gt;, &lt;code&gt;toCSS&lt;/code&gt;, and &lt;code&gt;&amp;lt;Match&amp;gt;&lt;/code&gt;, we were able to reduce the bundle size (according to &lt;a href="https://bundlephobia.com/package/@blocz/react-responsive@4.0.0" rel="noopener noreferrer"&gt;bundlephobia&lt;/a&gt;) from 3.8kB in the v3.0.3 to 2.7kB in the v4.0.0 minified (and from 1.7kB to 1.3kB gzipped).&lt;/p&gt;

&lt;p&gt;This wasn’t a goal per se, but we can always appreciate reducing the impact we have on our end customers.&lt;/p&gt;

</description>
      <category>react</category>
      <category>responsive</category>
      <category>package</category>
    </item>
    <item>
      <title>Intl.Segmenter(): Don't use string.split() nor string.length</title>
      <dc:creator>Ayc0</dc:creator>
      <pubDate>Tue, 25 Jul 2023 13:04:00 +0000</pubDate>
      <link>https://dev.to/ayc0/intlsegmenter-dont-use-stringsplit-nor-stringlength-dh6</link>
      <guid>https://dev.to/ayc0/intlsegmenter-dont-use-stringsplit-nor-stringlength-dh6</guid>
      <description>&lt;ol&gt;
&lt;li&gt;TL;DR&lt;/li&gt;
&lt;li&gt;
Explanation

&lt;ol&gt;
&lt;li&gt;Definitions&lt;/li&gt;
&lt;li&gt;UTF-16&lt;/li&gt;
&lt;li&gt;String.prototype.length&lt;/li&gt;
&lt;li&gt;Unicode composition&lt;/li&gt;
&lt;li&gt;Emoji Sequence&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;

Intl.Segmenter

&lt;ol&gt;
&lt;li&gt;Browser compatibility&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;The other day I was playing with JS and I saw 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="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="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;é&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// 2, not the same output as the line before&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;é&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;|&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// 'e|́'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Yes, all of those are valid, you can copy paste them 😅)&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;As an image is worth 1000 words:&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%2Ffty25unybapraxyaslkr.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%2Ffty25unybapraxyaslkr.png" alt="Grapheme vs code unit vs code point" width="800" height="282"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter" rel="noopener noreferrer"&gt;Intl.Segmenter&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;seg&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;Intl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Segmenter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&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;granularity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;grapheme&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;seg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;segment&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="nx"&gt;length&lt;/span&gt;
&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;seg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;segment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;é&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)].&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;
&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Explanation
&lt;/h2&gt;

&lt;p&gt;This article will talk about &lt;em&gt;character&lt;/em&gt; vs &lt;em&gt;code unit&lt;/em&gt; vs &lt;em&gt;code point&lt;/em&gt; vs &lt;em&gt;grapheme&lt;/em&gt; vs &lt;em&gt;glyph&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Definitions
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;Character&lt;/code&gt;: generic term that can mean any of the other 4 terms.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;Code Unit&lt;/code&gt;: A code unit is the smallest unit of data in UTF-16 encoding. In UTF-16, each code unit is 16 bits (2 bytes) in size. It can represent a part of a character or a complete character, depending on the character's Unicode value.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;Code Point&lt;/code&gt;: A code point is a numerical value assigned to a specific character in the Unicode standard. It's a unique identifier for each character and is typically represented in hexadecimal. For example, the code point for the letter "A" is U+0041. In UTF-16, every code point is composed by either 1 or 2 code unit.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;Grapheme&lt;/code&gt;: A grapheme is the smallest unit of a writing system that carries meaning and represents a single "user-perceived" character. In UTF-16, every grapheme is composed by at least 1 code point. Not all code points are part of graphemes, like the zero-width non-joiner.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;Glyph&lt;/code&gt;: A glyph is a visual representation or image of a character. It is the actual shape or form of a character as it appears on a screen or in print. A single character can have multiple glyphs associated with it, representing different typographic variations or font styles.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can check &lt;a href="https://stackoverflow.com/questions/27331819/whats-the-difference-between-a-character-a-code-point-a-glyph-and-a-grapheme" rel="noopener noreferrer"&gt;https://stackoverflow.com/questions/27331819/whats-the-difference-between-a-character-a-code-point-a-glyph-and-a-grapheme&lt;/a&gt; for more details.&lt;/p&gt;

&lt;h3&gt;
  
  
  UTF-16
&lt;/h3&gt;

&lt;p&gt;JavaScript uses &lt;a href="https://en.wikipedia.org/wiki/UTF-16" rel="noopener noreferrer"&gt;UTF-16&lt;/a&gt; (and not UTF-8 as opposed as many other languages. To note: UTF-8 would also have all of those issues).&lt;/p&gt;

&lt;p&gt;In UTF-16, &lt;em&gt;characters&lt;/em&gt; are encoded in 16-bit chunks (&lt;em&gt;code unit&lt;/em&gt;). For instance &lt;code&gt;$&lt;/code&gt; is encoded in hexadecimal into &lt;code&gt;0024&lt;/code&gt; (thus its notation &lt;code&gt;U+0024&lt;/code&gt; or &lt;code&gt;'\u0024'&lt;/code&gt;); and &lt;code&gt;€&lt;/code&gt; is encoded as &lt;code&gt;20AC&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Problem: Using a 16-bit &lt;em&gt;code unit&lt;/em&gt; can only result in 65536 possible characters, so how do we represent the other &lt;em&gt;characters&lt;/em&gt;? UTF-16 has a system where it can use 2 &lt;em&gt;code units&lt;/em&gt; to encode some &lt;em&gt;code points&lt;/em&gt;. For instance &lt;code&gt;𐐷&lt;/code&gt; is the &lt;em&gt;code point&lt;/em&gt; &lt;code&gt;U+10437&lt;/code&gt; will be encoded as &lt;code&gt;D801 DC37&lt;/code&gt; (a high surrogate &lt;code&gt;D801&lt;/code&gt; and a low surrogate &lt;code&gt;DC37&lt;/code&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%2Fsd3zmt59k7stx73bffh2.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%2Fsd3zmt59k7stx73bffh2.png" alt="$, €, and 𐐷 encoded in UTF-16 in code units" width="800" height="197"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  String.prototype.length
&lt;/h3&gt;

&lt;p&gt;According &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/length" rel="noopener noreferrer"&gt;MDN&lt;/a&gt;, the &lt;code&gt;length&lt;/code&gt; is based on &lt;em&gt;code units&lt;/em&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The length data property of a String value contains the length of the string in UTF-16 code units.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This explains why for 🙌 (U+1F64C) or 𐐷 (U+10437), using &lt;code&gt;.length&lt;/code&gt; doesn’t return 1 as those are encoded in 2 code units:&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="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="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// U+10437&lt;/span&gt;
&lt;span class="c1"&gt;// 2&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="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// U+1F64C&lt;/span&gt;
&lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One possible fix for this case is to use &lt;code&gt;iterators&lt;/code&gt;. According to &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/length" rel="noopener noreferrer"&gt;MDN&lt;/a&gt; again, iterators work on code points (they say characters, but they mean code points):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Since length counts code units instead of characters, if you want to get the number of characters, you can first split the string with its iterator, which iterates by characters&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And it does work indeed…&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="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="nx"&gt;length&lt;/span&gt; &lt;span class="c1"&gt;// U+10437&lt;/span&gt;
&lt;span class="c1"&gt;// 1&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="nx"&gt;length&lt;/span&gt; &lt;span class="c1"&gt;// U+1F64C&lt;/span&gt;
&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;é&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;
&lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;🙌🏾&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;… but not for all &lt;em&gt;characters&lt;/em&gt;. Why?&lt;/p&gt;

&lt;h3&gt;
  
  
  Unicode composition
&lt;/h3&gt;

&lt;p&gt;Another specificity of Unicode is that it can combines multiple code points to form a grapheme. This is called canonical equivalence&lt;br&gt;
(see &lt;a href="https://unicode.org/reports/tr15/#Canon_Compat_Equivalence" rel="noopener noreferrer"&gt;https://unicode.org/reports/tr15/#Canon_Compat_Equivalence&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;For instance the letter "Ç" can either be the code point for this character, or the code point for "C" followed by the diacritic mark "◌̧"&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%2F5dhf9yjoybqftvm6l3a7.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%2F5dhf9yjoybqftvm6l3a7.png" alt="Ç &amp;lt;-&amp;gt; C+◌̧" width="800" height="157"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can also use normalization NFD and NFC to switch between the precomposed and decomposed forms (see &lt;a href="https://unicode.org/reports/tr15/#Norm_Forms):" rel="noopener noreferrer"&gt;https://unicode.org/reports/tr15/#Norm_Forms):&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Many characters are known as canonical composites, or precomposed characters. In the D forms, they are decomposed; in the C forms, they are &lt;em&gt;usually&lt;/em&gt; precomposed.&lt;/p&gt;
&lt;/blockquote&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%2Fuxrpqqryzmd2ol5od655.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%2Fuxrpqqryzmd2ol5od655.png" alt="" width="369" height="169"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This explains why &lt;code&gt;é&lt;/code&gt;’s length was either 1 or 2 in the initial example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  decomposed form → 2 code points&lt;/li&gt;
&lt;li&gt;  precomposed form → 1 code point&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In JavaScript, you can use &lt;code&gt;String.prototype.normalize&lt;/code&gt; (&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize" rel="noopener noreferrer"&gt;MDN&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="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="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;é&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NFD&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;é&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NFD&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NFC&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Emoji Sequence
&lt;/h3&gt;

&lt;p&gt;Similarly to character compositions, emojis can be combined together with special characters (this is not an exhaustive list):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Skin tone modifiers&lt;/strong&gt; can be used to customize the color skin of emojis&lt;br&gt;
For instance "🙌🏾" is composed of "🙌" + "🏾" (&lt;a href="https://emojipedia.org/medium-dark-skin-tone/" rel="noopener noreferrer"&gt;Medium-Dark Skin Tone modifier&lt;/a&gt;)&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;🙌🏾&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="c1"&gt;// ['🙌', '🏾']&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Zero-Width Joiner&lt;/strong&gt; (ZWJ) can be used to merge some emojis together&lt;br&gt;
For instance "😮‍💨" is composed of "😮" + "‍" (&lt;a href="https://emojipedia.org/zero-width-joiner/" rel="noopener noreferrer"&gt;ZWJ&lt;/a&gt;) + "💨"&lt;br&gt;
And "👩‍👩‍👧‍👦" is composed of each individual family members plus ZWJs:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;👩‍👩‍👧‍👦&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="c1"&gt;// ['👩', '‍', '👩', '‍', '👧', '‍', '👦']&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Variation Selectors&lt;/strong&gt; can be used to choose a different glyph variant for a code point&lt;br&gt;
For instance "ℹ️" is composed of "ℹ" + "️" (&lt;a href="https://emojipedia.org/variation-selector-16/" rel="noopener noreferrer"&gt;Variation Selector-16&lt;/a&gt; to force the display as an emoji)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Intl.Segmenter
&lt;/h2&gt;

&lt;p&gt;In 2021, the TC39 committee added to ECMAScript &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter" rel="noopener noreferrer"&gt;Intl.Segmenter&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Intl.Segmenter object enables locale-sensitive text segmentation, enabling you to get meaningful items (graphemes, words or sentences) from a string.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once a locale is picked, you can use &lt;code&gt;.segment&lt;/code&gt; to generate an iterator with each grapheme of a 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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;seg&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;Intl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Segmenter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&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;granularity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;grapheme&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;grapheme&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;seg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;segment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hélô 👩‍👩‍👧‍👦 🙌🏾&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="nx"&gt;grapheme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;segment&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// "H"&lt;/span&gt;
&lt;span class="c1"&gt;// "é"&lt;/span&gt;
&lt;span class="c1"&gt;// "l"&lt;/span&gt;
&lt;span class="c1"&gt;// "ô"&lt;/span&gt;
&lt;span class="c1"&gt;// " "&lt;/span&gt;
&lt;span class="c1"&gt;// "👩‍👩‍👧‍👦"&lt;/span&gt;
&lt;span class="c1"&gt;// " "&lt;/span&gt;
&lt;span class="c1"&gt;// "🙌🏾"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if you want to get the number of grapheme (like &lt;code&gt;.length&lt;/code&gt;), you can transform it to an array first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;seg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;segment&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="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// 1&lt;/span&gt;

&lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;seg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;segment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;é&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)].&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Browser compatibility
&lt;/h3&gt;

&lt;p&gt;Sadly, at the date of the writing (July 2023) is not supported on Firefox yet – check on &lt;a href="https://caniuse.com/mdn-javascript_builtins_intl_segmenter" rel="noopener noreferrer"&gt;caniuse.com&lt;/a&gt;. You can track &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1423593" rel="noopener noreferrer"&gt;this issue&lt;/a&gt; if you want to follow its development.&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%2Fbe4uvsnzw835ppsh6tqq.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%2Fbe4uvsnzw835ppsh6tqq.png" alt="Browser compatibility table" width="792" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>intl</category>
      <category>encoding</category>
      <category>unicode</category>
    </item>
    <item>
      <title>TypeScript 5.0: new mode bundler &amp; ESM</title>
      <dc:creator>Ayc0</dc:creator>
      <pubDate>Tue, 11 Apr 2023 14:43:00 +0000</pubDate>
      <link>https://dev.to/ayc0/typescript-50-new-mode-bundler-esm-1jic</link>
      <guid>https://dev.to/ayc0/typescript-50-new-mode-bundler-esm-1jic</guid>
      <description>&lt;p&gt;In TypeScript 5.0, 2 new features were released:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;moduleResolution: bundler&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;allowImportingTsExtensions&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(&lt;a href="https://devblogs.microsoft.com/typescript/announcing-typescript-5-0/#moduleresolution-bundler" rel="noopener noreferrer"&gt;see release note&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Let’s dive into what these allow us to solve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;Let’s take this piece of code:&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;// INPUT&lt;/span&gt;
&lt;span class="c1"&gt;// foo.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// bar.ts&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;foo&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;./foo&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; sets a new bar`&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 want to transpile this plain JavaScript, with &lt;code&gt;module: CommonJS&lt;/code&gt; set in our &lt;code&gt;tsconfig.json&lt;/code&gt;, we’d get something 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="c1"&gt;// OUTPUT&lt;/span&gt;
&lt;span class="c1"&gt;// foo.js&lt;/span&gt;
&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// bar.js&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;foo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; sets a new bar`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But now you could tell me:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Wait, I thought that JS now supports import/export? Also, isn’t this require/exports only for Node.js?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yes, you’re totally right! import/export are part of &lt;a href="https://nodejs.org/api/esm.html" rel="noopener noreferrer"&gt;ESM (ECMAScript Modules)&lt;/a&gt;. And require/exports are indeed only valid in Node.js.&lt;/p&gt;

&lt;p&gt;Let’s try to use ESM!&lt;/p&gt;

&lt;h3&gt;
  
  
  ESM
&lt;/h3&gt;

&lt;p&gt;You can enable this via &lt;code&gt;module: es6 / es2020 / esnext / node16&lt;/code&gt; in your &lt;code&gt;tsconfig.json&lt;/code&gt;.&lt;br&gt;
With the same input, we’d get:&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;// OUTPUT&lt;/span&gt;
&lt;span class="c1"&gt;// foo.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// bar.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;foo&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;./foo&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; sets a new bar`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;“Wait, what’s the catch here? This seems to be valid!”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the ECMAScript spec, they mention that imports need to have a &lt;strong&gt;file extension&lt;/strong&gt;, so &lt;code&gt;import { foo } from './foo';&lt;/code&gt; is &lt;strong&gt;not&lt;/strong&gt; valid (see in &lt;a href="https://nodejs.org/api/esm.html#mandatory-file-extensions" rel="noopener noreferrer"&gt;Node.js’s doc&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Which extension should we pick?
&lt;/h3&gt;

&lt;p&gt;Okay, let’s say I want to build for ESM, what extension should I write in my source code?&lt;br&gt;
Let’s try a different code samples:&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;code&gt;.ts&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;With a &lt;code&gt;.ts&lt;/code&gt; extension:&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;// INPUT&lt;/span&gt;
&lt;span class="c1"&gt;// foo.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// bar.ts&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;foo&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;./foo.ts&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; sets a new bar`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we’d get this code in JS:&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;// OUTPUT&lt;/span&gt;
&lt;span class="c1"&gt;// foo.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// bar.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;foo&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;./foo.ts&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; sets a new bar`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see that this &lt;strong&gt;cannot&lt;/strong&gt; work: &lt;code&gt;foo.ts&lt;/code&gt; doesn’t exist in the generated code as the generated file is named &lt;code&gt;foo.js&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;.js&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Okay, so what about with a &lt;code&gt;.js&lt;/code&gt; file then?&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;// INPUT&lt;/span&gt;
&lt;span class="c1"&gt;// foo.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// bar.ts&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;foo&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;./foo.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; sets a new bar`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would generate:&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;// OUTPUT&lt;/span&gt;
&lt;span class="c1"&gt;// foo.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// bar.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;foo&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;./foo.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; sets a new bar`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This indeed works!&lt;br&gt;
Hoorah! We have some working code with TypeScript &amp;amp; ESM 🎉&lt;br&gt;
This is the official way of supporting ESM in TS files: &lt;a href="https://www.typescriptlang.org/docs/handbook/esm-node.html" rel="noopener noreferrer"&gt;https://www.typescriptlang.org/docs/handbook/esm-node.html&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The only issue is that we have to write down &lt;code&gt;foo.js&lt;/code&gt; in the source TS file, which is weird 😕 (as the file doesn’t exist during dev time).&lt;/p&gt;
&lt;h4&gt;
  
  
  Why are extensions required in ESM?
&lt;/h4&gt;

&lt;p&gt;Due to how the web works, it has to work with files that are fully pre-determined, otherwise when writing &lt;code&gt;import './foo'&lt;/code&gt;, if it implemented the same logic as node, we’d have to download: &lt;code&gt;foo.js&lt;/code&gt;, &lt;code&gt;foo.cjs&lt;/code&gt;, &lt;code&gt;foo.mjs&lt;/code&gt;, &lt;code&gt;foo/index.js&lt;/code&gt;, etc.&lt;br&gt;
So for browsers, it makes more sense to treat the import as the reference.&lt;/p&gt;
&lt;h4&gt;
  
  
  Why isn’t the transform of the extension automatically done by TypeScript?
&lt;/h4&gt;

&lt;p&gt;TypeScript never rewrites module specifiers in its JavaScript emit.&lt;/p&gt;

&lt;p&gt;I don’t have the exact reasons why they don’t do it, but to me this would counterproductive as there are more differences between CommonJS &amp;amp; ESM (see &lt;a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-7.html#type-in-packagejson-and-new-extensions" rel="noopener noreferrer"&gt;TS v4.7 release note&lt;/a&gt;).&lt;br&gt;
So enforcing the use of the extensions, is a great way to tell people that we are in ESM, and also is closer to the underlying generated JS logic.&lt;/p&gt;
&lt;h3&gt;
  
  
  Summary of the issue
&lt;/h3&gt;

&lt;p&gt;To support ESM, we need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Change all imports use &lt;code&gt;.js&lt;/code&gt;, &lt;code&gt;.cjs&lt;/code&gt;, or &lt;code&gt;.mjs&lt;/code&gt; -&amp;gt; large update,&lt;/li&gt;
&lt;li&gt;The new imports don’t match the source files,&lt;/li&gt;
&lt;li&gt;Tools like webpack/esbuild/deno do support &lt;code&gt;.ts&lt;/code&gt; files in paths, so why is this an issue?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Solution: &lt;code&gt;allowImportingTsExtensions&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;In TypeScript 5.0, a new option was added: &lt;code&gt;allowImportingTsExtensions&lt;/code&gt;, which allows users to use &lt;code&gt;.ts&lt;/code&gt; in imports!&lt;/p&gt;

&lt;p&gt;The only requirement with it, is that we &lt;a href="https://www.typescriptlang.org/tsconfig#allowImportingTsExtensions" rel="noopener noreferrer"&gt;&lt;strong&gt;cannot emit code anymore&lt;/strong&gt;&lt;/a&gt; (as this wouldn’t produce any valid JavaScript code).&lt;/p&gt;

&lt;p&gt;So either &lt;code&gt;noEmit: true&lt;/code&gt; needs to be set, or &lt;code&gt;emitDeclarationOnly: true&lt;/code&gt; (as importing &lt;code&gt;.ts&lt;/code&gt; files is allowed in &lt;code&gt;.d.ts&lt;/code&gt; files).&lt;/p&gt;

&lt;p&gt;We can now write the following (useful for Deno for instance):&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;// INPUT&lt;/span&gt;
&lt;span class="c1"&gt;// foo.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// bar.ts&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;foo&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;./foo.ts&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; sets a new bar`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Solution: &lt;code&gt;moduleResolution: bundler&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Enabling the &lt;code&gt;.ts&lt;/code&gt; extension is already a bonus, but why should we write any extension at all when the code is bundled anyway by Webpack, Vite, esbuild, Parcel, rollup, swc?&lt;/p&gt;

&lt;p&gt;If your &lt;strong&gt;code is bundled&lt;/strong&gt;, there is now a new option that you can use starting with TypeScript 5.0: &lt;code&gt;moduleResolution: bundler&lt;/code&gt; (&lt;a href="https://github.com/microsoft/TypeScript/pull/51669" rel="noopener noreferrer"&gt;see PR that added it&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;This:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tells TypeScript that you’re code will be bundled by another tool, and thus to loosen the rules with imports (can have no extension, or use &lt;code&gt;.ts&lt;/code&gt; extensions)&lt;/li&gt;
&lt;li&gt;requires to use &lt;code&gt;module&lt;/code&gt; set to &lt;code&gt;es2015&lt;/code&gt; or later (which enables parsing &lt;code&gt;exports&lt;/code&gt; in package.json and other changes)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note: Using es2015 or later will enable new rules in TS (e.g.: like disabling &lt;code&gt;require&lt;/code&gt;), so it won’t be a no-op.&lt;/p&gt;

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

&lt;p&gt;Module resolution in TypeScript is complex, and has evolved over the years. TypeScript 5.0 added 2 new tools to allow adapting the tool in more contexts than before. But they all come with requirements.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How does CSS work? The specificity</title>
      <dc:creator>Ayc0</dc:creator>
      <pubDate>Mon, 30 Jan 2023 16:03:00 +0000</pubDate>
      <link>https://dev.to/ayc0/how-does-css-work-the-specificity-2fak</link>
      <guid>https://dev.to/ayc0/how-does-css-work-the-specificity-2fak</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Let’s take this piece of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
  &lt;span class="nc"&gt;.red&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nc"&gt;.blue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&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;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"red blue"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Hello world&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What is the color of the text? Let’s try it out:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/ayc0/embed/NWBBGbG?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Congratulations if you picked blue!&lt;/p&gt;

&lt;p&gt;The reason why the color appears blue is because the selector was defined last.&lt;/p&gt;




&lt;p&gt;Now let’s try the same thing with:&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;style&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;#id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nc"&gt;.red&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&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;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"blue"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Hello world&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What is the color of the text now? Let’s try it out:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/ayc0/embed/qByymPr?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;It appears green. But why so?&lt;/p&gt;

&lt;h2&gt;
  
  
  Specificity
&lt;/h2&gt;

&lt;h3&gt;
  
  
  General rule
&lt;/h3&gt;

&lt;p&gt;CSS uses multiple rules to determine how to apply styles and selectors to elements. One of them is the &lt;strong&gt;specificity&lt;/strong&gt;: this is a score computed for each selector. Once all of them are computed, CSS will pick the selector with the &lt;strong&gt;highest&lt;/strong&gt; specificity.&lt;/p&gt;

&lt;p&gt;Let’s circle back to our 2nd example. If we display the specificity of each selectors, we have:&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="nf"&gt;#id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c"&gt;/* Specificity: (1, 0, 0) → WINS */&lt;/span&gt;
&lt;span class="nc"&gt;.red&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c"&gt;/* Specificity: (0, 1, 0) */&lt;/span&gt;
&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c"&gt;/* Specificity: (0, 0, 1) */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which explains why the text appears &lt;code&gt;green&lt;/code&gt;: &lt;code&gt;#id&lt;/code&gt; has the highest specificity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Egality
&lt;/h3&gt;

&lt;p&gt;If 2 selectors have the same specificity, then the last defined will take over, which explains the situation in our 1st example:&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;.red&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c"&gt;/* Specificity: (0, 1, 0) */&lt;/span&gt;
&lt;span class="nc"&gt;.blue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c"&gt;/* Specificity: (0, 1, 0) &amp;amp; last one → WINS */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to compute the specificity
&lt;/h2&gt;

&lt;h2&gt;
  
  
  General rules
&lt;/h2&gt;

&lt;p&gt;The specificity is a list of 3 elements: &lt;code&gt;(A, B, C)&lt;/code&gt;, where:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;A&lt;/code&gt; is the ID selectors (e.g., &lt;code&gt;#example&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;B&lt;/code&gt; is the class selectors (e.g., &lt;code&gt;.example&lt;/code&gt;), attributes selectors (e.g., &lt;code&gt;[type="radio"]&lt;/code&gt;) and pseudo-classes (e.g., &lt;code&gt;:hover&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;C&lt;/code&gt; is the type selectors (e.g., &lt;code&gt;h1&lt;/code&gt;) and pseudo-elements (e.g., &lt;code&gt;::before&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;If you want to check the differences between pseudo-classes (like &lt;code&gt;:hover&lt;/code&gt;) and pseudo-elements (like &lt;code&gt;::before&lt;/code&gt;), you can check this post: &lt;a href="https://dev.to/ayc0/css-before-vs-before-1d35"&gt;https://dev.to/ayc0/css-before-vs-before-1d35&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Edge cases
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Universal_selectors" rel="noopener noreferrer"&gt;&lt;code&gt;*&lt;/code&gt;&lt;/a&gt; (universal selector) and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:where" rel="noopener noreferrer"&gt;&lt;code&gt;:where()&lt;/code&gt;&lt;/a&gt; have &lt;strong&gt;no specificity&lt;/strong&gt; &lt;code&gt;(0, 0, 0)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:is(…)&lt;/code&gt;, &lt;code&gt;:not(…)&lt;/code&gt;, and &lt;code&gt;:has(…)&lt;/code&gt; pseudo-classes have the specificity of their most specific complex selector in their selector list argument.
For instance: &lt;code&gt;:not(.class)&lt;/code&gt; will have the same specificity as &lt;code&gt;.class&lt;/code&gt; (aka &lt;code&gt;(0, 1, 0)&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:nth-child(…)&lt;/code&gt; and &lt;code&gt;:nth-last-child(…)&lt;/code&gt; have the specificity of their most specific complex selector in their selector list argument &lt;strong&gt;plus&lt;/strong&gt; their own specificity
For instance: &lt;code&gt;:nth-child(2n of .class)&lt;/code&gt; will have the same specificity as &lt;code&gt;.class&lt;/code&gt; + &lt;code&gt;:nth-child&lt;/code&gt; (aka &lt;code&gt;(0, 1, 0) + (0, 1, 0) = (0, 2, 0)&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Examples
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.a.b.c&lt;/code&gt; -&amp;gt; &lt;code&gt;(0, 3, 0)&lt;/code&gt; (3 classes)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;div#id&lt;/code&gt; -&amp;gt; &lt;code&gt;(1, 0, 1)&lt;/code&gt; (1 id + 1 element)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;html&lt;/code&gt; -&amp;gt; &lt;code&gt;(0, 0, 1)&lt;/code&gt; | &lt;code&gt;:root&lt;/code&gt; -&amp;gt; &lt;code&gt;(0, 1, 0)&lt;/code&gt; (which in &lt;a href="https://dev.to/ayc0/lightdark-mode-corrections-5e19#-raw-root-endraw-with-class-names"&gt;https://dev.to/ayc0/lightdark-mode-corrections-5e19#-raw-root-endraw-with-class-names&lt;/a&gt; I said that they both represent the same element with just different specificity&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;span &amp;gt; a[href$=".org"]:not([disabled])&lt;/code&gt; -&amp;gt; &lt;code&gt;(0, 2, 2)&lt;/code&gt; (2 elements (span &amp;amp; a) &amp;amp; 2 attributes selectors (href &amp;amp; not disabled)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Combining selectors
&lt;/h3&gt;

&lt;p&gt;When writing CSS rules, multiple selectors can be passed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"password"&lt;/span&gt;&lt;span class="o"&gt;],&lt;/span&gt;
&lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="nd"&gt;:focus&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="nf"&gt;#myApp&lt;/span&gt; &lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="nd"&gt;:required&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&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 those cases, it won’t create 1 giant agglomerated selector. Instead CSS will treat those as 3 distinct rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"password"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="nd"&gt;:focus&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="nf"&gt;#myApp&lt;/span&gt; &lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="nd"&gt;:required&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then it’ll continue as normal: find the selector with the highest specificity and apply it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you want to know how to bump or increase the specificity of a selector, I’ll shortly release a separate article about it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Inline style
&lt;/h3&gt;

&lt;p&gt;There are 2 ways of injecting styles in HTML:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CSS style sheet that use selectors with specificity,&lt;/li&gt;
&lt;li&gt;inline style in HTML.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Inline style doesn't use selectors, and thus cannot have specificity. So how do they fit in this system?&lt;/p&gt;

&lt;p&gt;We can think about it as a 4th element in the list &lt;code&gt;I&lt;/code&gt;: &lt;code&gt;(I, A, B, C)&lt;/code&gt;, that has more importance than the 3 others we’ve seen previously.&lt;/p&gt;

&lt;p&gt;With this logic, in this example, "Hello World" should appear purple:&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;style&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;#id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nc"&gt;.red&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&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;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"blue"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"color: RebeccaPurple"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Hello world
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/ayc0/embed/VwBBqeo?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;!important&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Even if &lt;code&gt;!important&lt;/code&gt; has nothing to do with specificity, it allows styles to be applied no matter what their specificity.&lt;/p&gt;

&lt;p&gt;Which means that in this example: even if &lt;code&gt;div&lt;/code&gt; has the lowest specificity, its style will be applied and the text will appear blue:&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;style&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;#id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nc"&gt;.red&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;blue&lt;/span&gt; &lt;span class="cp"&gt;!important&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;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"blue"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"color: RebeccaPurple"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Hello world
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/ayc0/embed/YzjjdYy?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Another article dedicated to how &lt;code&gt;!important&lt;/code&gt; works will be released in the future.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tools
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Parsel
&lt;/h4&gt;

&lt;p&gt;When selectors become too complex, you can use &lt;a href="https://projects.verou.me/parsel/" rel="noopener noreferrer"&gt;Parsel&lt;/a&gt;, a library built by &lt;a href="https://lea.verou.me/" rel="noopener noreferrer"&gt;Lea Verou&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fumseei3lx99qfkg9ip65.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%2Fumseei3lx99qfkg9ip65.png" alt="Parsel parsing " width="800" height="154"&gt;&lt;/a&gt; .bar + div.k1.k2 [id='baz']:nth-child(2n of .k3):not(:where(#yolo))::before" and determining its specificity (1,6,2)"/&amp;gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  VSCode
&lt;/h4&gt;

&lt;p&gt;Similarly, VSCode can parse selectors and display their specificity on hover.&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%2F0inob8t4o2jow1j5rwc2.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%2F0inob8t4o2jow1j5rwc2.png" alt="VSCode parsing " width="800" height="263"&gt;&lt;/a&gt; .bar + div.k1.k2 [id='baz']:nth-child(2n):not(:where(#yolo))::before""/&amp;gt;&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to learn CSS with games</title>
      <dc:creator>Ayc0</dc:creator>
      <pubDate>Thu, 26 Jan 2023 10:39:06 +0000</pubDate>
      <link>https://dev.to/ayc0/how-to-learn-css-with-games-2eg0</link>
      <guid>https://dev.to/ayc0/how-to-learn-css-with-games-2eg0</guid>
      <description>&lt;p&gt;Learning CSS isn’t the easiest. But the community helped solving that by creating a lot of interactive games online (as the best way to learn is with games).&lt;/p&gt;

&lt;h3&gt;
  
  
  Selectors
&lt;/h3&gt;

&lt;p&gt;If you want to learn CSS selectors, you can try out &lt;a href="https://flukeout.github.io/" rel="noopener noreferrer"&gt;CSS Diner 🍱&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuj4ziz0im8b8z5rg6iy5.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%2Fuj4ziz0im8b8z5rg6iy5.png" alt="Select the apple on the plate&amp;lt;br&amp;gt;
" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Flexbox
&lt;/h3&gt;

&lt;p&gt;For flexbox, you can try out &lt;a href="https://flexboxfroggy.com/" rel="noopener noreferrer"&gt;Flexbox Froggy 🐸&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F633kujzp457cxv10g553.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%2F633kujzp457cxv10g553.png" alt="Frogs needing alignment with CSS flex" width="800" height="269"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Grid
&lt;/h3&gt;

&lt;p&gt;And finally, you can learn CSS Grid with &lt;a href="https://cssgridgarden.com/" rel="noopener noreferrer"&gt;Grid Garden 🧑‍🌾&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F461qqw3byx7kbdyhcmzi.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%2F461qqw3byx7kbdyhcmzi.png" alt="Water all plants with CSS Grid" width="800" height="334"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>css</category>
      <category>learn</category>
    </item>
    <item>
      <title>CSS :before vs ::before &amp; :after vs ::after</title>
      <dc:creator>Ayc0</dc:creator>
      <pubDate>Tue, 17 Jan 2023 15:05:00 +0000</pubDate>
      <link>https://dev.to/ayc0/css-before-vs-before-1d35</link>
      <guid>https://dev.to/ayc0/css-before-vs-before-1d35</guid>
      <description>&lt;p&gt;When reading CSS code, we sometimes see code using &lt;code&gt;:before&lt;/code&gt; and other times with &lt;code&gt;::before&lt;/code&gt; (same for &lt;code&gt;::after&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Is there a difference between the 2 notations? Is one correct?&lt;/p&gt;

&lt;h2&gt;
  
  
  A bit of history
&lt;/h2&gt;

&lt;p&gt;In CSS2, the syntax used at the time was &lt;code&gt;:before&lt;/code&gt;. This was confusing because CSS also had &lt;em&gt;selectors&lt;/em&gt; like &lt;code&gt;:hover&lt;/code&gt;, but they both had different semantic meanings.&lt;/p&gt;

&lt;p&gt;So in &lt;a href="https://drafts.csswg.org/selectors-3/#gen-content" rel="noopener noreferrer"&gt;Selectors Level 3&lt;/a&gt;, they decided to change the syntax for &lt;code&gt;:before&lt;/code&gt; to &lt;code&gt;::before&lt;/code&gt; (and for legacy reasons, we can still use &lt;code&gt;:before&lt;/code&gt;, but it is now deprecated).&lt;br&gt;
The &lt;code&gt;:&lt;/code&gt; notation isn’t deprecated as a whole, instead the old syntax was split into two:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; &lt;code&gt;:&lt;/code&gt; now represents pseudo-classes (and is still valid for &lt;code&gt;:hover&lt;/code&gt; for instance),&lt;/li&gt;
&lt;li&gt; &lt;code&gt;::&lt;/code&gt; represents pseudo-elements (and should be used for &lt;code&gt;::before&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;:pseudo-class&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Pseudo-classes represent variations of a state of an element.&lt;br&gt;
When the condition is satisfied, the &lt;strong&gt;whole&lt;/strong&gt; element is selected.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A CSS pseudo-class is a keyword added to a selector that specifies a special state of the selected element(s).&lt;/p&gt;
&lt;/blockquote&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%2F8pbfu10w6omks0zpp7pn.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%2F8pbfu10w6omks0zpp7pn.png" alt="Visual representation of  raw `span::hover` endraw " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:hover&lt;/code&gt; matches an element on hover&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:not(p)&lt;/code&gt; matches an element if it's not a &lt;code&gt;p&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:last-of-type&lt;/code&gt; matches an element that is the last of its siblings, and also matches a certain type selector.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See the full list in &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes" rel="noopener noreferrer"&gt;MDN&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;::pseudo-element&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;On the other hand, pseudo-elements are &lt;strong&gt;parts&lt;/strong&gt; of the original element. They represent fake HTML nodes within the selected element.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A CSS &lt;strong&gt;pseudo-element&lt;/strong&gt; is a keyword added to a selector that lets you style a specific part of the selected element(s).&lt;/p&gt;
&lt;/blockquote&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%2Fmsnfwiraud02blaskatr.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%2Fmsnfwiraud02blaskatr.png" alt="Visual representation of  raw `span::first-letter` endraw " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;::before&lt;/code&gt; corresponds to a slot just before this element,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;::first-line&lt;/code&gt; selects the first line in the current element,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;::first-letter&lt;/code&gt; retrieves the very first letter of the element.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See the full list in &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements" rel="noopener noreferrer"&gt;MDN&lt;/a&gt;&lt;/p&gt;

</description>
      <category>html</category>
      <category>webdev</category>
      <category>fundamentals</category>
      <category>css</category>
    </item>
    <item>
      <title>Light/dark mode: Corrections</title>
      <dc:creator>Ayc0</dc:creator>
      <pubDate>Mon, 16 Jan 2023 14:44:27 +0000</pubDate>
      <link>https://dev.to/ayc0/lightdark-mode-corrections-5e19</link>
      <guid>https://dev.to/ayc0/lightdark-mode-corrections-5e19</guid>
      <description>&lt;p&gt;In this post, I want to fix some mistakes I made in other posts, and also include new elements I discovered on this topic since I wrote them.&lt;/p&gt;

&lt;p&gt;When this will be released, all other related posts will also be edited to avoid mentioning those errors. I wanted to reference all of them for posterity.&lt;/p&gt;

&lt;h2&gt;
  
  
  CSS color scheme
&lt;/h2&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/ayc0" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F202017%2F2247c005-889d-4cd2-8de9-7e8812d2c713.png" alt="ayc0"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/ayc0/light-dark-mode-the-lazy-way-4j71" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Light/dark mode: the lazy way&lt;/h2&gt;
      &lt;h3&gt;Ayc0 ・ May 29 '21&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#css&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;In this post, I only mentioned the meta tag with the name &lt;code&gt;color-scheme&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;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"color-scheme"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"light dark"&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;But I forgot to mention that this can also be set in the CSS (&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme" rel="noopener noreferrer"&gt;see MDN&lt;/a&gt;):&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="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;color-scheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;light&lt;/span&gt; &lt;span class="n"&gt;dark&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;I also wrote:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; this will work on both Chrome and Safari, but not Firefox&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This has been fixed in Firefox 96 🎉 (see &lt;a href="https://caniuse.com/mdn-css_properties_color-scheme" rel="noopener noreferrer"&gt;caniuse&lt;/a&gt;).&lt;/p&gt;
&lt;h2&gt;
  
  
  Native system colors
&lt;/h2&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/ayc0" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F202017%2F2247c005-889d-4cd2-8de9-7e8812d2c713.png" alt="ayc0"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/ayc0/light-dark-mode-the-lazy-way-4j71" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Light/dark mode: the lazy way&lt;/h2&gt;
      &lt;h3&gt;Ayc0 ・ May 29 '21&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#css&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



&lt;p&gt;In this post, I only mentioned the use of &lt;code&gt;color-scheme&lt;/code&gt;. But there is also another powerful tool available to us: native system themed colors.&lt;/p&gt;

&lt;p&gt;In CSS, you can say that a color should follow the system color for multiple semantic elements, like &lt;code&gt;LinkText&lt;/code&gt;, or &lt;code&gt;Canvas&lt;/code&gt; (background color):&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%2Fitysdasc4tlijyvg12og.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%2Fitysdasc4tlijyvg12og.png" alt="A few examples of system colors" width="800" height="505"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The best is that those colors will have automated variants in dark mode (which is why they should have been mentioned in the “Lazy way” post).&lt;/p&gt;

&lt;p&gt;For the whole list of system colors, and their semantic meaning, you can out the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/system-color" rel="noopener noreferrer"&gt;MDN page&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;:root&lt;/code&gt; with class names
&lt;/h2&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/ayc0" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F202017%2F2247c005-889d-4cd2-8de9-7e8812d2c713.png" alt="ayc0"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/ayc0/light-dark-mode-user-input-ai1" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Light/dark mode: user input&lt;/h2&gt;
      &lt;h3&gt;Ayc0 ・ May 30 '21&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#css&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;In this post, I wrote:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;And as we are using classnames, we cannot use :root as before.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is wrong 😕. When we read &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:root" rel="noopener noreferrer"&gt;its MDN page&lt;/a&gt;, it says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;:root&lt;/code&gt; &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS" rel="noopener noreferrer"&gt;CSS&lt;/a&gt; &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes" rel="noopener noreferrer"&gt;pseudo-class&lt;/a&gt; matches the root element of a tree representing the document. In HTML, &lt;code&gt;:root&lt;/code&gt; represents the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/html" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt;&lt;/a&gt; element and is identical to the selector &lt;code&gt;html&lt;/code&gt;, except that its &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity" rel="noopener noreferrer"&gt;specificity&lt;/a&gt; is higher.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After some tests, I can confirm that the following works fine:&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="nd"&gt;:root&lt;/span&gt;&lt;span class="nc"&gt;.dark-mode&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* Works great! */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;/* Equivalent to html but with a greater specificity */&lt;/span&gt;
&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="nc"&gt;.dark-mode&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* Works great! */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;:root&lt;/code&gt; has specificity of &lt;code&gt;(0, 1, 0)&lt;/code&gt;, and &lt;code&gt;html&lt;/code&gt; has a specificity of &lt;code&gt;(0, 0, 1)&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Using data attributes instead of class names
&lt;/h2&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/ayc0" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F202017%2F2247c005-889d-4cd2-8de9-7e8812d2c713.png" alt="ayc0"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/ayc0/light-dark-mode-user-input-ai1" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Light/dark mode: user input&lt;/h2&gt;
      &lt;h3&gt;Ayc0 ・ May 30 '21&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#css&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



&lt;p&gt;In this post, I mentioned that we were using 2 classes &lt;code&gt;.light&lt;/code&gt; and &lt;code&gt;.dark&lt;/code&gt;. And that we were using this function to control those classes:&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;colorScheme&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;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;meta[name="color-scheme"]&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="nf"&gt;applyTheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&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="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;colorScheme&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;theme&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 issue with it, is that it overrides all classes set on the body. This is fine for this post, as we don’t have any other classes, but it may not be in your own application.&lt;/p&gt;

&lt;p&gt;A more realistic function would be something 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;colorScheme&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;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;meta[name="color-scheme"]&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="nf"&gt;applyTheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&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="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;light&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="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dark&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="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;colorScheme&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;theme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You can see that it's a bit tedious to have to remove all classes, especially if you start to add more themes, like low/high contrast, etc.&lt;/p&gt;

&lt;p&gt;A better solution would be to use data attributes, to which we can add the correction we did for the &lt;code&gt;color-scheme&lt;/code&gt;, and for the root &lt;code&gt;:root&lt;/code&gt;:&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="nd"&gt;:root&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"light"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;color-scheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;light&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nd"&gt;:root&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"dark"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;color-scheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--background&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And to set 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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;applyTheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&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;documentElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;(&lt;code&gt;document.documentElement&lt;/code&gt; is the &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; node, see on &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/documentElement" rel="noopener noreferrer"&gt;MDN&lt;/a&gt;)&lt;/p&gt;
&lt;h2&gt;
  
  
  Real time system mode
&lt;/h2&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/ayc0" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F202017%2F2247c005-889d-4cd2-8de9-7e8812d2c713.png" alt="ayc0"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/ayc0/light-dark-mode-system-mode-user-preferences-1fcd" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Light/dark mode: system mode + user preferences&lt;/h2&gt;
      &lt;h3&gt;Ayc0 ・ May 31 '21&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#css&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



&lt;p&gt;In this post, I explained how to use a custom picker and how to use a &lt;code&gt;system&lt;/code&gt; mode.&lt;/p&gt;

&lt;p&gt;I forgot to say that this system mode won’t follow the current theme users have on their machine. Instead it just computes this theme when the mode is picked.&lt;/p&gt;

&lt;p&gt;This mechanism is more complicated and can be explained in its own post. But in the meantime, the React implementation includes this feature:&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/ayc0" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F202017%2F2247c005-889d-4cd2-8de9-7e8812d2c713.png" alt="ayc0"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/ayc0/light-dark-mode-react-implementation-3aoa" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Light/dark mode: React implementation&lt;/h2&gt;
      &lt;h3&gt;Ayc0 ・ Jun 24 '21&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#css&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#react&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>css</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Proper cross-fade in CSS</title>
      <dc:creator>Ayc0</dc:creator>
      <pubDate>Thu, 06 Oct 2022 14:40:01 +0000</pubDate>
      <link>https://dev.to/ayc0/proper-cross-fade-in-css-388m</link>
      <guid>https://dev.to/ayc0/proper-cross-fade-in-css-388m</guid>
      <description>&lt;p&gt;In &lt;a href="https://www.youtube.com/watch?v=PYSOnC2CrD8" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=PYSOnC2CrD8&lt;/a&gt;, &lt;a class="mentioned-user" href="https://dev.to/surma"&gt;@surma&lt;/a&gt; and &lt;a class="mentioned-user" href="https://dev.to/jakearchibald"&gt;@jakearchibald&lt;/a&gt; talked about what a proper crossfade is, why it is complicated to do with the current technologies. And at the end of the video, they mentioned that they just proposed this to the CSS working group.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a proper cross fade?
&lt;/h2&gt;

&lt;p&gt;If we want to transition from a text &lt;code&gt;A&lt;/code&gt; to a text &lt;code&gt;B&lt;/code&gt;, the easiest is to vary the opacity from 1 to 0 on &lt;code&gt;A&lt;/code&gt;, and from 0 to 1 on &lt;code&gt;B&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The main issue with this method is that, for instance, during the middle of the animation, both will have a 50% opacity. Due to how CSS composes layers, we'll still have a color with 75% opacity. But in cross fade, the opacity should always be 100% as we are animating from the start to the end, without any notion of "this is on top of the other".&lt;/p&gt;

&lt;p&gt;Here you can see the difference between improper and proper cross fade:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Incorrect 75% opacity&lt;/th&gt;
&lt;th&gt;Fixed version&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&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%2Fkqwj9v3ap0pxazqo77pk.png" alt="double 0.5 opacity" width="800" height="801"&gt;&lt;/td&gt;
&lt;td&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%2Fimlrcqgemsvdatj0al51.png" alt="double 0.5 opacity with proper cross fade" width="800" height="801"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  How to achieve this
&lt;/h2&gt;

&lt;p&gt;The way to do it is to add &lt;code&gt;mix-blend-mode: plus-lighter&lt;/code&gt; on the second text, so that CSS knows how to blend this layer with the other ones.&lt;/p&gt;

&lt;p&gt;In addition to setting the &lt;code&gt;mix-blend-mode&lt;/code&gt;, we should add &lt;code&gt;isolation: isolate&lt;/code&gt; on the container so that CSS knows that the composition operation should only be computed within this element, and that we shouldn't also apply it with the full background.&lt;/p&gt;

&lt;p&gt;Here is the MDN article on &lt;code&gt;mix-blend-mode&lt;/code&gt;: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/ayc0/embed/wvjPpQq?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>TypeScript 4.9: satisfies operator</title>
      <dc:creator>Ayc0</dc:creator>
      <pubDate>Sun, 25 Sep 2022 13:44:45 +0000</pubDate>
      <link>https://dev.to/ayc0/typescript-49-satisfies-operator-1e4i</link>
      <guid>https://dev.to/ayc0/typescript-49-satisfies-operator-1e4i</guid>
      <description>&lt;p&gt;In their v4.9, the TypeScript team is releasing a new operator: &lt;code&gt;satisfies&lt;/code&gt; (see blog post &lt;a href="https://devblogs.microsoft.com/typescript/announcing-typescript-4-9-beta/#the-satisfies-operator" rel="noopener noreferrer"&gt;https://devblogs.microsoft.com/typescript/announcing-typescript-4-9-beta/#the-satisfies-operator&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Purpose
&lt;/h2&gt;

&lt;p&gt;The purpose of &lt;code&gt;satisfies&lt;/code&gt; is to enforce a constraint on a variable, without changing its type.&lt;/p&gt;

&lt;p&gt;For instance, you want to say that a color is "either a string, or a RGB tuple", which would give something like that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;RGB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;red&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;green&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RGB&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;string&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;myColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;red&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;But now, we don't know whether &lt;code&gt;myColor.value&lt;/code&gt; is a string or a tuple. So we cannot do something like &lt;code&gt;myColor.value.toUpperCase()&lt;/code&gt; (even if it's actually a string).&lt;/p&gt;

&lt;p&gt;In TS 4.9, it'll be possible to do this (&lt;a href="https://www.typescriptlang.org/play?ts=4.9.0-dev.20220921#code/C4TwDgpgBASg4gISgXigJwgQwCYHsB2ANiFANobYBcU+ArgLYBGEaANFAOYYT7V1Mt2jQrQh8GzNAF0A3AChQkKAGFchXGhRQA3lABumEWNiIoAHygBnYGgCW+DlAC+8uQGMC1qPRCr1m1F0DI2oAcgpQ5ytMYFtLADNbCEsVNQ0ZKAB6TKgAdw0Aa0t3T2BvEABJfA80DDdgPw0tIMNRagBGAAZOqMsYuMTk1P8M7KhgAAs0XFyUlmm0OTkfRrQAOmDRNeBcAFUwSDRlTEsIAAoASlGc4NtsKFxD-oIoE-LVqDjXqxt7DiA" rel="noopener noreferrer"&gt;TypeScript Playground&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;RGB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;red&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;green&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RGB&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;string&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;myColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;satisfies&lt;/span&gt; &lt;span class="nx"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// works&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myIncorrectColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;satisfies&lt;/span&gt; &lt;span class="nx"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// throws error&lt;/span&gt;

&lt;span class="nx"&gt;myColor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// valid operation as myColor is a string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Combining &lt;code&gt;as const&lt;/code&gt; and satisfies
&lt;/h2&gt;

&lt;p&gt;As expected, you combine &lt;code&gt;as const&lt;/code&gt; and &lt;code&gt;satisfies&lt;/code&gt; (&lt;a href="https://www.typescriptlang.org/play?ts=4.9.0-dev.20220921#code/C4TwDgpgBASg4gISgXigJwgQwCYHsB2ANiFANobYBcU+ArgLYBGEaANFAOYYT7V1Mt2jQrQh8GzNAF0A3AChQkKAGFchXGhSxEUAD5QAzsDQBLfB3lyAxgSNQwmQhGDBoqAN5yo39BCpkAJgBWIPYABnCpVi8fLggeagAiAGIwsIAzdLTE6J8oYVFqUgBGVgDWAGYouQBfQ0xgEwN0kwgDWAgbNGwAHiNTc3ZVdTQAPksbfAM1CAA6dQ4ACgcnFzm4ngBKeQB6HbyDw7yAPQB+OQvJuyvgTHxgAAVHZ1ctTzyKIuDQqAjf6ryG14UBSaUy2VyPgKYjIpXKVWidUw7Ru9UazVa7RgnQ0vX6Zg4QzUGnGl1sM3muCWNzuj2ea1mQO2cj2RzZ7O8ZzkQA" rel="noopener noreferrer"&gt;TypeScript Playground&lt;/a&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;RGB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;red&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;green&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;RGB&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;string&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;palette&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;red&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;255&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;green&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#00ff00&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;satisfies&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Color&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="nx"&gt;palette&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;green&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;//                   ^? green is string&lt;/span&gt;


&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;constantPalette&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;red&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;255&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;green&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#00ff00&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;satisfies&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Color&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="nx"&gt;constantPalette&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;green&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;//                          ^? green is "#00ff00"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: the order matters. While &lt;code&gt;as const satisfies &amp;lt;type&amp;gt;&lt;/code&gt; works, the opposite isn't true: &lt;code&gt;satisfies &amp;lt;type&amp;gt; as const&lt;/code&gt; will throw a TS error (&lt;a href="https://www.typescriptlang.org/play?ts=4.9.0-dev.20220921#code/C4TwDgpgBASg4gISgXigJwgQwCYHsB2ANiFANobYBcU+ArgLYBGEaANFAOYYT7V1Mt2jQrQh8GzNAF0A3AChQkKAGFchXGhSxEUAD5QAzsDQBLfB3lyAxgSNQzAN0yET2AArOIwYNFQBvOSgg9AgqMgAmAFZI9gAGOKlWQOCuCB5qACIAYljYgDM83Iyk4KhhUWpSAEZWcNYAZkS5AF9DTGATAzyTCANYCBs0bAAeI1NzdjGzDj1tBAA+KEw+m3wjGSgAek2oYAALNFwAdz7MfCgWQ7QgA" rel="noopener noreferrer"&gt;TypeScript Playground&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;RGB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;red&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;green&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;RGB&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;string&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;invalidPalette&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;red&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;255&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;green&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#00ff00&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;satisfies&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;RGB&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// throws an error&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>typescript</category>
      <category>operator</category>
    </item>
    <item>
      <title>CRA vs Parcel</title>
      <dc:creator>Ayc0</dc:creator>
      <pubDate>Mon, 05 Sep 2022 23:03:26 +0000</pubDate>
      <link>https://dev.to/ayc0/cra-vs-parcel-d08</link>
      <guid>https://dev.to/ayc0/cra-vs-parcel-d08</guid>
      <description>&lt;p&gt;When working a new React project, there are a lot of frameworks / bundlers that we can choose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://create-react-app.dev/" rel="noopener noreferrer"&gt;create-react-app&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;NextJS&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://parceljs.org/" rel="noopener noreferrer"&gt;Parcel&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://vitejs.dev/" rel="noopener noreferrer"&gt;Vite&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;&lt;a href="https://astro.build/" rel="noopener noreferrer"&gt;astro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;and many others.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here I only want to focus on comparable tools: I'll only look into frameworks to build a React single page app.&lt;/p&gt;

&lt;p&gt;As I haven't used Vite that much, I'll only compare create-react-app and Parcel.&lt;/p&gt;

&lt;h2&gt;
  
  
  CRA
&lt;/h2&gt;

&lt;p&gt;Create React App is one of the first tools released to manage a React SPA. It's maintained by Facebook and the open source community.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;p&gt;It comes with a long of tools out of the box:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a seamless webpack &amp;amp; babel config,&lt;/li&gt;
&lt;li&gt;a test runner,&lt;/li&gt;
&lt;li&gt;an ESLint integration (integrated with an overlay),&lt;/li&gt;
&lt;li&gt;TypeScript / Flow,&lt;/li&gt;
&lt;li&gt;Fast Refresh,&lt;/li&gt;
&lt;li&gt;CSS modules / SASS,&lt;/li&gt;
&lt;li&gt;web vitals,&lt;/li&gt;
&lt;li&gt;and many other good things out of the box.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's also the default template proposed by &lt;a href="https://codesandbox.io/" rel="noopener noreferrer"&gt;Code Sandbox&lt;/a&gt; when starting a new React Project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;p&gt;The first drawback is related to its primary advantage: it provides out of the box configuration for most tools. But as soon as you want to have a little customisation, CRA won't be nice to you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you want to customize the webpack configuration, you either need to &lt;a href="https://create-react-app.dev/docs/available-scripts/#npm-run-eject" rel="noopener noreferrer"&gt;eject&lt;/a&gt;, or to work against the package (with yarn patch, forking react-scripts, or using &lt;a href="https://github.com/dilanx/craco" rel="noopener noreferrer"&gt;CRACO&lt;/a&gt; which is the easiest). But none of them are officially maintained by the CRA team.&lt;/li&gt;
&lt;li&gt;You cannot have a version of ESLint or babel locally that differs from react-scripts' version, otherwise the build will crash.&lt;/li&gt;
&lt;li&gt;You cannot have any ESLint error / warning, otherwise the build will crash.&lt;/li&gt;
&lt;li&gt;Adding new loaders can be tricky.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also noticed over the years a few issues with particular versions of Node, or yarn.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parcel
&lt;/h2&gt;

&lt;p&gt;Parcel is a zero configuration build tool. It comes out of the box with a lot of resolvers, plus it proposes a large set of plugins.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;p&gt;Just like CRA, Parcel comes out of the box with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no config (or almost no config),&lt;/li&gt;
&lt;li&gt;TypeScript resolver,&lt;/li&gt;
&lt;li&gt;Fast Refresh,&lt;/li&gt;
&lt;li&gt;CSS modules / SASS.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks to &lt;a href="https://parceljs.org/features/plugins/" rel="noopener noreferrer"&gt;its plugins system&lt;/a&gt;, if something doesn't come out of the box, the community can come with their own plugins (for instance a MDX plugin).&lt;/p&gt;

&lt;p&gt;As Parcel doesn't depend on babel nor on webpack, it also installs way fewer packages, so the node_modules folder is way smaller.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;p&gt;As Parcel is just the bundler, it doesn't come with a test runner, nor any CLI tool to simply start a project.&lt;/p&gt;

&lt;p&gt;Note: About test runners, for smaller projects we don't necessarily need one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code samples
&lt;/h2&gt;

&lt;h3&gt;
  
  
  CRA
&lt;/h3&gt;

&lt;p&gt;I'll compare the same architecture between CRA and Parcel. Let's start with the initial CRA project with &lt;code&gt;npx create-react-app test-cra&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npx create-react-app test-cra
Need to install the following packages:
  create-react-app@5.0.1
Ok to proceed? (y)
npm WARN deprecated tar@2.2.2: This version of tar is no longer supported, and will not receive security updates. Please upgrade asap.

Creating a new React app in /code/test-cra.

Installing packages. This might take a couple of minutes.
Installing react, react-dom, and react-scripts with cra-template...


added 1394 packages in 58s

209 packages are looking for funding
  run `npm fund` for details

Initialized a git repository.

Installing template dependencies using npm...

added 56 packages in 4s

209 packages are looking for funding
  run `npm fund` for details
Removing template package using npm...


removed 1 package, and audited 1450 packages in 1s

209 packages are looking for funding
  run `npm fund` for details

6 high severity vulnerabilities

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.

Created git commit.

Success! Created test-cra at /code/test-cra
Inside that directory, you can run several commands:

  npm start
    Starts the development server.

  npm run build
    Bundles the app into static files for production.

  npm test
    Starts the test runner.

  npm run eject
    Removes this tool and copies build dependencies, configuration files
    and scripts into the app directory. If you do this, you can’t go back!

We suggest that you begin by typing:

  cd test-cra
  npm start

Happy hacking!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see that the install took almost &lt;strong&gt;a minute&lt;/strong&gt;, and it installed 1394 packages, including &lt;strong&gt;6 high severity vulnerabilities&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The project itself 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%2Ff7hssdymps5lg2b164zj.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%2Ff7hssdymps5lg2b164zj.png" alt="Content of the project after the npx command for CRA" width="800" height="518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Migration to Parcel
&lt;/h3&gt;

&lt;p&gt;Let's try to replicate the same architecture with Parcel.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm i           
npm WARN deprecated stable@0.1.8: Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility

added 171 packages, and audited 172 packages in 5s

72 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see here that the install is way faster: only 5s, and fewer packages were installed.&lt;/p&gt;

&lt;p&gt;Except for modifying a bit the dependencies and the public/index.html file, I haven't changed the rest. (The &lt;code&gt;devDependencies&lt;/code&gt; were automatically added by parcel in the following image)&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%2F1krgnawdnkc7h24s90ez.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%2F1krgnawdnkc7h24s90ez.png" alt="Content of the project after npm i for Parcel" width="800" height="476"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here are the modifications I did to the index.html:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I removed a "magical" env variable &lt;code&gt;%PUBLIC_URL%&lt;/code&gt; and instead used direct paths,&lt;/li&gt;
&lt;li&gt;Added a hard coded &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag:&lt;/li&gt;
&lt;/ul&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%2F3ky8dvgyrc6shb9trauz.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%2F3ky8dvgyrc6shb9trauz.png" alt="diff between CRA's index.html and Parcel's index.html" width="800" height="637"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;I stopped using CRA when working for my React projects, and instead I always go to Parcel:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it's &lt;strong&gt;way&lt;/strong&gt; faster (both for the install &lt;strong&gt;and&lt;/strong&gt; to run) and smaller,&lt;/li&gt;
&lt;li&gt;it comes with fewer "magical" tools that cannot be configured,&lt;/li&gt;
&lt;li&gt;it's easier to customize and to maintain.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>parcel</category>
      <category>bundler</category>
    </item>
    <item>
      <title>Semver: The unknown buildMetadata</title>
      <dc:creator>Ayc0</dc:creator>
      <pubDate>Thu, 14 Jul 2022 01:30:39 +0000</pubDate>
      <link>https://dev.to/ayc0/semver-the-unknown-parts-271</link>
      <guid>https://dev.to/ayc0/semver-the-unknown-parts-271</guid>
      <description>&lt;p&gt;I was reading &lt;a href="https://semver.org/" rel="noopener noreferrer"&gt;semver's spec&lt;/a&gt; and I noticed something weird in the regex:&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%2Fdyn2hb56xwjex3cyd6hr.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%2Fdyn2hb56xwjex3cyd6hr.png" alt="Screenshot of semver spec saying " width="800" height="134"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the 1st time that I ever encountered the mention of &lt;code&gt;buildmetadata&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let's deconstruct that a bit
&lt;/h3&gt;

&lt;p&gt;When you read the regex, it mentions at the beginning the required &lt;code&gt;major&lt;/code&gt;, &lt;code&gt;minor&lt;/code&gt;, and &lt;code&gt;patch&lt;/code&gt;: a valid semver version needs to be at least &lt;code&gt;MAJOR.MINOR.PATCH&lt;/code&gt;, for instance &lt;code&gt;1.2.3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then the version can contain an option &lt;code&gt;prerelease&lt;/code&gt; tag starting with a &lt;strong&gt;&lt;code&gt;-&lt;/code&gt;&lt;/strong&gt;, for instance &lt;code&gt;1.2.3-hello&lt;/code&gt; and this prelease tag can be anything made of alpha numerics (0-9 or a-z or A-Z), &lt;code&gt;.&lt;/code&gt; and &lt;code&gt;-&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But what surprised me is the last one: the &lt;code&gt;buildmetadata&lt;/code&gt; prefixed with a &lt;strong&gt;&lt;code&gt;+&lt;/code&gt;&lt;/strong&gt; (same thing as the prerelease so any alpha numerics, or &lt;code&gt;.&lt;/code&gt;, or &lt;code&gt;-&lt;/code&gt;).&lt;br&gt;
So for instance &lt;code&gt;1.2.3+build&lt;/code&gt; is valid, and so is &lt;code&gt;1.2.3-beta.1+build.linux&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Verification
&lt;/h3&gt;

&lt;p&gt;Just to be sure, I run this in runkit, and indeed it can properly parse &lt;code&gt;1.2.3-pre.release.4+build.meta.5.6&lt;/code&gt; as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  major: 1,
  minor: 2,
  patch: 3,
  prerelease: ["pre", "release", 4], // here 4 is even a number
  build: ["build", "meta", "5", "6"], // but here 5 and 6 are strings
  version: "1.2.3-pre.release.4",
  raw: "1.2.3-pre.release.4+build.meta.5.6"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See for yourselves:&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%2Fniejqzhlppdlxyaj1tez.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%2Fniejqzhlppdlxyaj1tez.png" alt="semver properly parses  raw `1.2.3-pre.release.4.5+build.meta.6.7` endraw " width="800" height="707"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Discussion
&lt;/h3&gt;

&lt;p&gt;I've seen plenty of times the prerelease being used (and I used it myself a few times too).&lt;/p&gt;

&lt;p&gt;For instance, React uses it a lot:&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%2Fp00o9cthqgf0s4dlhymu.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%2Fp00o9cthqgf0s4dlhymu.png" alt="Sample of React versions on NPM with a lot of prereleases" width="800" height="526"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My topic for a conversation with you is: Have you ever seen this used anywhere on NPM (or else where)? And if so, for what purpose?&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>npm</category>
      <category>semver</category>
      <category>versioning</category>
    </item>
    <item>
      <title>Yarn.lock: How to Update it</title>
      <dc:creator>Ayc0</dc:creator>
      <pubDate>Sun, 05 Sep 2021 21:58:59 +0000</pubDate>
      <link>https://dev.to/ayc0/yarn-lock-how-to-update-it-1fa2</link>
      <guid>https://dev.to/ayc0/yarn-lock-how-to-update-it-1fa2</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Knowing how to read a &lt;code&gt;yarn.lock&lt;/code&gt; file is important: it lists the packages that your application will end up using. Sure, your dependencies are listed in your &lt;code&gt;package.json&lt;/code&gt;, it only lists your direct deps, not the deps of your deps.&lt;/p&gt;

&lt;p&gt;So, if you really care about your app, you should be able to read this lock file, and here is another post about this:&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/ayc0" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F202017%2F2247c005-889d-4cd2-8de9-7e8812d2c713.png" alt="ayc0"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/ayc0/yarn-lock-how-to-read-it-1f7h" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Yarn.lock: How to Read it&lt;/h2&gt;
      &lt;h3&gt;Ayc0 ・ Jul 27 '21&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#yarn&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#config&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#lockfile&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;If you spot something weird in the lockfile, this article will tell you how to fix it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Problem&lt;/li&gt;
&lt;li&gt;
Solutions

&lt;ol&gt;
&lt;li&gt;Manually editing the lock file&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;resolutions&lt;/code&gt; field&lt;/li&gt;
&lt;li&gt;Removing the &lt;code&gt;yarn.lock&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;yarn dedupe&lt;/code&gt; (recommended)&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;

Bonus: listing all versions of a package

&lt;ol&gt;
&lt;li&gt;Yarn 1&lt;/li&gt;
&lt;li&gt;Yarn 2+&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Conclusion&lt;/li&gt;

&lt;/ol&gt;

&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;Note: I'll use the semver syntax, more information on it here: &lt;a href="https://jubianchi.github.io/semver-check/" rel="noopener noreferrer"&gt;https://jubianchi.github.io/semver-check/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's say you depend on a module &lt;code&gt;A&lt;/code&gt; that itself depends on &lt;code&gt;B&lt;/code&gt; with the version &lt;code&gt;^1.1.1&lt;/code&gt;. When &lt;code&gt;A&lt;/code&gt; will be installed, yarn will resolve the latest version of &lt;code&gt;B&lt;/code&gt; matching this version range (let say here &lt;code&gt;1.1.4&lt;/code&gt;). Now you'll have in your lock file something like: "A depends on B@^1.1.1, resolved resolved to 1.1.4".&lt;/p&gt;

&lt;p&gt;Later, you want to install a package &lt;code&gt;C&lt;/code&gt;, depending on &lt;code&gt;B@^1.1.5&lt;/code&gt;. And when &lt;code&gt;C&lt;/code&gt; is added, &lt;code&gt;B@1.1.5&lt;/code&gt; just came out. So you end up with &lt;code&gt;B@1.1.4&lt;/code&gt; &lt;strong&gt;AND&lt;/strong&gt; &lt;code&gt;B@1.1.5&lt;/code&gt; in your node_modules.&lt;/p&gt;

&lt;p&gt;You ended up here:&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%2F4x6b8eid6ue1tyjzsy43.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%2F4x6b8eid6ue1tyjzsy43.png" alt="Illustration showing that A imports B@^1.1.1 resolved in B@1.1.4, and that C imports B@^1.1.5 resolved in B@1.1.5, resulting in having 2 versions of B" width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But ideally, you should end up like that:&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%2Fm4pt38rne6ghcz9rx3yj.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%2Fm4pt38rne6ghcz9rx3yj.png" alt="Illustration showing that A imports B@^1.1.1 resolved, and C imports B@^1.1.5, both resolved in B@1.1.5, resulting in having only 1 version of B" width="800" height="381"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;The behaviour is indeed intended: the main goal of lock file is to ensure that your dependencies won't change if you don't ask for it. As you didn't ask for an update of A, it shouldn't update neither it nor its dependencies. And as updating B from 1.1.4 to 1.1.5 could introduce some regression, &lt;code&gt;yarn&lt;/code&gt; won't update it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real world example:&lt;/strong&gt; you are using &lt;a href="https://github.com/facebook/create-react-app" rel="noopener noreferrer"&gt;&lt;code&gt;create-react-app&lt;/code&gt;&lt;/a&gt;, and you want to also to use &lt;a href="https://github.com/xojs/xo" rel="noopener noreferrer"&gt;&lt;code&gt;xo&lt;/code&gt;&lt;/a&gt;, as both come with their own version of ESLint pre-installed, you could end up with 2 ESLint installed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solutions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Manually editing the lock file
&lt;/h3&gt;

&lt;p&gt;I personally really like this solution, as this is the one that allows you to fully manipulate the resolution mechanism.&lt;/p&gt;

&lt;p&gt;With our previous example, we should have something like the following in the &lt;code&gt;yarn.lock&lt;/code&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;"B@^1.1.1":
  version "1.1.4"
  resolved "https://registry.yarnpkg.com/B-1.1.4.tgz#???"
  integrity sha512-???==

"B@^1.1.5":
  version "1.1.5"
  resolved "https://registry.yarnpkg.com/B-1.1.5.tgz#???"
  integrity sha512-???==
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can simply edit the file, and merge the 2 versions like that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"B@^1.1.1", "B@^1.1.5":
  version "1.1.5"
  resolved "https://registry.yarnpkg.com/B-1.1.5.tgz#???"
  integrity sha512-???==
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once this has been changed, we just have to run &lt;code&gt;yarn install&lt;/code&gt; and 💥, &lt;a href="mailto:B@1.1.4"&gt;B@1.1.4&lt;/a&gt; will no longer be installed, only &lt;a href="mailto:B@1.1.5"&gt;B@1.1.5&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;resolutions&lt;/code&gt; field
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Yarn&lt;/code&gt; comes with a custom &lt;code&gt;resolutions&lt;/code&gt; field you can set in your package.json&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"resolutions"&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;"B"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.1.5"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will force &lt;strong&gt;all&lt;/strong&gt; versions of B to resolve to this one version &lt;code&gt;1.1.5&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I don't like this approach, as it'll force all versions (even incompatible ones like a potential v2 that could also be used in your deps) to be updated to this unique one. So I'd reserve this for modules you &lt;strong&gt;know&lt;/strong&gt; cannot exist in multiple versions, but I wouldn't use it otherwise.&lt;/p&gt;

&lt;h3&gt;
  
  
  Removing the &lt;code&gt;yarn.lock&lt;/code&gt; file
&lt;/h3&gt;

&lt;p&gt;If you remove the lock file completely and then run &lt;code&gt;yarn install&lt;/code&gt;, yarn will re-resolve all versions to the latest allowed by their specified ranges, and thus fix all those duplicated deps.&lt;/p&gt;

&lt;p&gt;I don't recommend doing that as not all packages respect the semver convention. So you could introduce a lot of regressions in your code.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;yarn dedupe&lt;/code&gt; (recommended)
&lt;/h3&gt;

&lt;p&gt;If you're using yarn 2+, you have access to the command &lt;code&gt;yarn dedupe B&lt;/code&gt; (to dedupe all the B packages).&lt;/p&gt;

&lt;p&gt;If you're running on yarn 2+, I strongly recommend using this, as it's the easiest and safest method of all of those listed here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://yarnpkg.com/cli/dedupe" rel="noopener noreferrer"&gt;https://yarnpkg.com/cli/dedupe&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: listing all versions of a package
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Yarn 1
&lt;/h3&gt;

&lt;p&gt;If you using yarn 1, you can use &lt;code&gt;yarn list --pattern &amp;lt;package-name&amp;gt;&lt;/code&gt; to see all the different versions (and where they are coming from) of a package:&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%2Fmcsxmz3rhti0lro89ur0.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%2Fmcsxmz3rhti0lro89ur0.png" alt="output of yarn 1' " width="496" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://classic.yarnpkg.com/en/docs/cli/list" rel="noopener noreferrer"&gt;https://classic.yarnpkg.com/en/docs/cli/list&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Yarn 2+
&lt;/h3&gt;

&lt;p&gt;Yarn berry (version 2 and above), has the command &lt;code&gt;yarn why&lt;/code&gt; (it already existed in yarn 1, but the output was completely different).&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%2Fep7g6avdbbj7qgalznb6.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%2Fep7g6avdbbj7qgalznb6.png" alt="Output of the command " width="632" height="860"&gt;&lt;/a&gt;", showing all the versions of this package installed, why it was installed, what version range was required each time, and which versions were resolved"/&amp;gt;&lt;/p&gt;

&lt;p&gt;The main difference between &lt;code&gt;yarn list&lt;/code&gt; in yarn 1 and &lt;code&gt;yarn why&lt;/code&gt; in yarn 2+ is that, in addition to having the version installed + the parent that required this package, you also have the version ranges that were requested each time.&lt;/p&gt;

&lt;p&gt;Also, the tree is flatten here to only have the most meaningful information. But if you want to have a deep tree (like in yarn 1), you can run &lt;code&gt;yarn why &amp;lt;package&amp;gt; -R&lt;/code&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%2Fg7z3svnxfq8oz43ogycn.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%2Fg7z3svnxfq8oz43ogycn.png" alt="Output of the command " width="800" height="862"&gt;&lt;/a&gt; -R", showing the same results as before, but also including all of the parent deps of those deps, recursively"/&amp;gt;&lt;/p&gt;

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

&lt;p&gt;When working on removing duplicated packages, knowing how to read and modify your &lt;code&gt;yarn.lock&lt;/code&gt; file is quite empowering.&lt;/p&gt;

&lt;p&gt;And if you're running yarn 2+, you can just use &lt;code&gt;yarn dedupe &amp;lt;package&amp;gt;&lt;/code&gt;, which will save you a lot of work.&lt;/p&gt;

</description>
      <category>yarn</category>
      <category>config</category>
      <category>lockfile</category>
    </item>
  </channel>
</rss>
