<?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: L Anil Kumar Singha</title>
    <description>The latest articles on DEV Community by L Anil Kumar Singha (@anilloutombam).</description>
    <link>https://dev.to/anilloutombam</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F381275%2F7c05e551-19bf-4978-b673-1fbb9db63c52.jpeg</url>
      <title>DEV Community: L Anil Kumar Singha</title>
      <link>https://dev.to/anilloutombam</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/anilloutombam"/>
    <language>en</language>
    <item>
      <title>Fixing an Infinite Loading State in the npmx Code Browser</title>
      <dc:creator>L Anil Kumar Singha</dc:creator>
      <pubDate>Mon, 03 Aug 2026 08:23:15 +0000</pubDate>
      <link>https://dev.to/anilloutombam/fixing-an-infinite-loading-state-in-the-npmx-code-browser-n25</link>
      <guid>https://dev.to/anilloutombam/fixing-an-infinite-loading-state-in-the-npmx-code-browser-n25</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/bugsmash"&gt;DEV's Summer Bug Smash: Clear the Lineup&lt;/a&gt; powered by &lt;a href="https://sentry.io/" rel="noopener noreferrer"&gt;Sentry&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Overview
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://npmx.dev" rel="noopener noreferrer"&gt;npmx&lt;/a&gt; is an open-source package explorer for the npm ecosystem. It helps developers inspect package metadata, releases, dependencies, documentation, comparisons, and published source files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug Fix or Performance Improvement
&lt;/h2&gt;

&lt;p&gt;The npmx code browser has a fallback for files that exceed its supported display size. It should show a “File too large” warning and provide an option to open the raw file.&lt;/p&gt;

&lt;p&gt;Instead, selecting an oversized file left the page displaying its loading state indefinitely.&lt;/p&gt;

&lt;p&gt;The issue can be reproduced here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://npmx.dev/package-code/@types/vscode/v/1.118.0/index.d.ts" rel="noopener noreferrer"&gt;https://npmx.dev/package-code/@types/vscode/v/1.118.0/index.d.ts&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The corrected behaviour can be verified on the PR preview:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://npmx-h3s403v0g-npmx.vercel.app/package-code/@types/vscode/v/1.118.0/index.d.ts" rel="noopener noreferrer"&gt;https://npmx-h3s403v0g-npmx.vercel.app/package-code/@types/vscode/v/1.118.0/index.d.ts&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;GitHub issue: &lt;a href="https://github.com/npmx-dev/npmx.dev/issues/2732" rel="noopener noreferrer"&gt;https://github.com/npmx-dev/npmx.dev/issues/2732&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pull request: &lt;a href="https://github.com/npmx-dev/npmx.dev/pull/3120" rel="noopener noreferrer"&gt;https://github.com/npmx-dev/npmx.dev/pull/3120&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The production fix is one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isFileTooLarge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It was added to the page’s loading-state calculation:&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;const&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;computed&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isViewingFile&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="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;treeStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;treeStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isFileTooLarge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;fileStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;fileStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pending&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;fileStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;idle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  My Improvements
&lt;/h2&gt;

&lt;p&gt;The page already knew when a selected file exceeded the size limit. In that situation, it intentionally skipped the file-content request.&lt;/p&gt;

&lt;p&gt;Because the request never started, its status remained &lt;code&gt;idle&lt;/code&gt;. The loading logic treated that status as if the file were still waiting to load, so the loading skeleton prevented the existing fallback from appearing.&lt;/p&gt;

&lt;p&gt;The new condition makes the page stop reporting a loading state when the file is already known to be too large. This allows the existing warning and raw-file action to render without changing the server limit or downloading unnecessary content.&lt;/p&gt;

&lt;p&gt;I also added a regression test that verifies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The large-file warning is displayed.&lt;/li&gt;
&lt;li&gt;The page does not remain in its loading state.&lt;/li&gt;
&lt;li&gt;The file-content endpoint is not called.&lt;/li&gt;
&lt;li&gt;The raw-file action points to the correct jsDelivr URL.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The code change is small, but it fixes an important state-handling edge case: an &lt;code&gt;idle&lt;/code&gt; request is not always waiting to begin. Sometimes the application has intentionally decided that it should not run.&lt;/p&gt;




&lt;p&gt;If you're interested in more of my open-source work and engineering projects, you can explore my &lt;a href="https://anilsingha.dev/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=npmx-infinite-loading" rel="noopener noreferrer"&gt;portfolio&lt;/a&gt; or follow my work on &lt;a href="https://github.com/anilloutombam" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>bugsmash</category>
      <category>opensource</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Fixing a Search Race Condition in npmx</title>
      <dc:creator>L Anil Kumar Singha</dc:creator>
      <pubDate>Sat, 01 Aug 2026 07:55:07 +0000</pubDate>
      <link>https://dev.to/anilloutombam/fixing-a-search-race-condition-in-npmx-4la3</link>
      <guid>https://dev.to/anilloutombam/fixing-a-search-race-condition-in-npmx-4la3</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/bugsmash"&gt;DEV's Summer Bug Smash: Clear the Lineup&lt;/a&gt; powered by &lt;a href="https://sentry.io/" rel="noopener noreferrer"&gt;Sentry&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Overview
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://npmx.dev" rel="noopener noreferrer"&gt;npmx&lt;/a&gt; is a modern browser for the npm registry. It provides package search, version timelines, dependency information, comparisons, and other tools for exploring npm packages.&lt;/p&gt;

&lt;p&gt;I've been contributing to npmx recently, mostly around search behavior and edge cases. One of those contributions started with a particularly interesting symptom:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The search failed the first time, but worked after a refresh.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug Fix or Performance Improvement
&lt;/h2&gt;

&lt;p&gt;The bug was reported in &lt;a href="https://github.com/npmx-dev/npmx.dev/issues/2617" rel="noopener noreferrer"&gt;issue #2617&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The reproduction was quite specific.&lt;/p&gt;

&lt;p&gt;With instant search disabled and a saved page size of 50 or higher:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the search page.&lt;/li&gt;
&lt;li&gt;Search for a package.&lt;/li&gt;
&lt;li&gt;No package results appear.&lt;/li&gt;
&lt;li&gt;The organization suggestion can still appear.&lt;/li&gt;
&lt;li&gt;Refresh the exact same page.&lt;/li&gt;
&lt;li&gt;The package results suddenly show up.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Same query. Same page size. Same application.&lt;/p&gt;

&lt;p&gt;The refresh behavior was the interesting part.&lt;/p&gt;

&lt;p&gt;If the packages didn't exist, refreshing shouldn't make them appear. And if the search request itself was fundamentally broken, I'd expect the second attempt to fail too.&lt;/p&gt;

&lt;p&gt;That pointed away from the search data itself and toward what was happening during the &lt;strong&gt;initialization of the page&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Following the timing
&lt;/h3&gt;

&lt;p&gt;npmx stores the user's preferred search page size locally.&lt;/p&gt;

&lt;p&gt;On the first navigation to the search page, however, the initial search could begin before that saved preference had finished loading.&lt;/p&gt;

&lt;p&gt;The sequence looked roughly like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Search page opens
        ↓
Initial search starts
(page size = 25)
        ↓
Saved preference loads
        ↓
Page size changes to 50
        ↓
fetchMore() runs
        ↓
Initial search is still pending
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Individually, none of these operations were wrong.&lt;/p&gt;

&lt;p&gt;The problem was &lt;strong&gt;when they happened relative to each other&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fetchMore()&lt;/code&gt; could run while the initial Algolia search was still pending.&lt;/p&gt;

&lt;p&gt;At that moment, the search result hadn't arrived yet. &lt;code&gt;fetchMore()&lt;/code&gt; could therefore read the temporary empty response and store that value in the search cache.&lt;/p&gt;

&lt;p&gt;Then the original search completed with the real package results.&lt;/p&gt;

&lt;p&gt;But it was too late.&lt;/p&gt;

&lt;p&gt;The empty cached value could take priority, leaving the UI showing no packages even though the search had successfully returned them.&lt;/p&gt;

&lt;p&gt;That also explained why refreshing appeared to magically fix the problem.&lt;/p&gt;

&lt;p&gt;It wasn't magic.&lt;/p&gt;

&lt;p&gt;The initialization timing had changed.&lt;/p&gt;

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

&lt;p&gt;The fix is in &lt;a href="https://github.com/npmx-dev/npmx.dev/pull/3109" rel="noopener noreferrer"&gt;npmx-dev/npmx.dev#3109&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Instead of allowing &lt;code&gt;fetchMore()&lt;/code&gt; to continue while the initial search is unresolved, it now checks whether that search is still pending and waits for it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;asyncData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pending&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;asyncData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refresh&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;dedupe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;defer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important detail here is:&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="nx"&gt;dedupe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;defer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I didn't want &lt;code&gt;fetchMore()&lt;/code&gt; to cancel the search that was already running and replace it with another request.&lt;/p&gt;

&lt;p&gt;It needed to &lt;strong&gt;join the existing in-flight request&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So the flow changed from something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Initial search ────────────────► package results
        │
        └── fetchMore()
                ↓
          reads empty state
                ↓
          empty value cached
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Initial search ────────────────► package results
                                      ↓
                               fetchMore() continues
                                      ↓
                               results preserved
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's a small change in code, but it changes the ordering guarantee between the two asynchronous operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Improvements
&lt;/h2&gt;

&lt;p&gt;The main fix was making &lt;code&gt;fetchMore()&lt;/code&gt; wait for the pending initial search before consuming its result.&lt;/p&gt;

&lt;p&gt;But a race-condition fix also needs a test that can reliably reproduce the timing that caused it.&lt;/p&gt;

&lt;p&gt;Otherwise, the test might pass simply because the operations happened in a convenient order that particular time.&lt;/p&gt;

&lt;p&gt;So I added a regression test that deliberately recreates the problematic sequence.&lt;/p&gt;

&lt;p&gt;The test:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Starts the initial Algolia search.&lt;/li&gt;
&lt;li&gt;Keeps that request pending.&lt;/li&gt;
&lt;li&gt;Changes the requested page size.&lt;/li&gt;
&lt;li&gt;Triggers the additional result-loading path.&lt;/li&gt;
&lt;li&gt;Resolves the original search.&lt;/li&gt;
&lt;li&gt;Verifies that the completed package results are preserved.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That was important because the test isn't relying on the race condition happening naturally.&lt;/p&gt;

&lt;p&gt;It &lt;strong&gt;controls the timing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;After the fix, users with a saved page size of 50 or higher get their package results on the first search without needing to refresh the page.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I took away from this bug
&lt;/h3&gt;

&lt;p&gt;What made this issue interesting wasn't the amount of code required to fix it.&lt;/p&gt;

&lt;p&gt;It was the symptom:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;It doesn't work the first time, but refreshing fixes it.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That can be a useful debugging clue.&lt;/p&gt;

&lt;p&gt;When persisted client state, initialization, caching, and asynchronous requests interact, a refresh can change the order in which those operations happen.&lt;/p&gt;

&lt;p&gt;In this case, the individual pieces were working.&lt;/p&gt;

&lt;p&gt;The initial search worked.&lt;/p&gt;

&lt;p&gt;The saved preference worked.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fetchMore()&lt;/code&gt; worked.&lt;/p&gt;

&lt;p&gt;The problem only appeared when they ran in a particular order.&lt;/p&gt;

&lt;p&gt;The final fix wasn't to make the search faster or add another request.&lt;/p&gt;

&lt;p&gt;It was simply to make one asynchronous operation respect another operation that was &lt;strong&gt;already in progress&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Sometimes fixing a race condition is less about doing more work and more about making sure the work you already have happens in the right order.&lt;/p&gt;




&lt;p&gt;If you're interested in more of my open-source work and engineering projects, you can explore my &lt;a href="https://anilsingha.dev/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=npmx-search-race-condition" rel="noopener noreferrer"&gt;portfolio&lt;/a&gt; or follow my work on &lt;a href="https://github.com/anilloutombam" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>bugsmash</category>
      <category>opensource</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Midnight Ramen: A Rainy CSS Art Love Letter to Comfort Food</title>
      <dc:creator>L Anil Kumar Singha</dc:creator>
      <pubDate>Fri, 31 Jul 2026 15:29:29 +0000</pubDate>
      <link>https://dev.to/anilloutombam/midnight-ramen-a-rainy-css-art-love-letter-to-comfort-food-hed</link>
      <guid>https://dev.to/anilloutombam/midnight-ramen-a-rainy-css-art-love-letter-to-comfort-food-hed</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/frontend-2026-07-29"&gt;Frontend Challenge - Comfort Food Edition, CSS Art&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Inspiration
&lt;/h2&gt;

&lt;p&gt;My inspiration was a warm bowl of ramen on a quiet, rainy night—the kind of meal that feels comforting before you even take the first bite.&lt;/p&gt;

&lt;p&gt;I wanted to capture more than the food itself, so I created a complete midnight ramen-shop scene. The steaming bowl is surrounded by a glowing lantern, falling rain, a handwritten order slip, shelves of ingredients, and a tiny shop cat peeking over the counter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/editor/anilloutombam/embed/019fb8b9-6447-7117-9662-e41035bfc2c4?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;You can also explore the source code on &lt;a href="https://github.com/anilloutombam/midnight-ramen-css-art" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Journey
&lt;/h2&gt;

&lt;p&gt;I created the illustration using HTML and CSS, without image assets or JavaScript. The bowl, broth, noodles, egg, chashu pork, nori, narutomaki, mushrooms, scallions, lantern, window, furniture, and cat are all composed from regular HTML elements.&lt;/p&gt;

&lt;p&gt;The visual details rely on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Layered CSS gradients&lt;/li&gt;
&lt;li&gt;Borders and border radii&lt;/li&gt;
&lt;li&gt;Pseudo-elements&lt;/li&gt;
&lt;li&gt;Transforms and clipping&lt;/li&gt;
&lt;li&gt;CSS custom properties&lt;/li&gt;
&lt;li&gt;Responsive media queries&lt;/li&gt;
&lt;li&gt;Subtle keyframe animations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The scene also includes CSS-only interactions. The chili-oil control changes the appearance of the broth and introduces small animated spice sparks. A compact day/night control changes the window, lantern, steam, and surrounding color palette without JavaScript.&lt;/p&gt;

&lt;p&gt;The ingredient labels can be revealed with a mouse or keyboard. I also included &lt;code&gt;prefers-reduced-motion&lt;/code&gt; support so visitors who disable animation receive a calmer version of the scene.&lt;/p&gt;

&lt;p&gt;The most challenging part was creating depth while keeping the markup understandable. The ramen bowl contains several overlapping layers, and each topping needs to remain recognizable without using an image. Careful positioning, contrast, shadows, and restrained animation helped the individual pieces feel like one cohesive illustration.&lt;/p&gt;

&lt;p&gt;I am particularly proud that the finished project requires only two files for the artwork: &lt;code&gt;index.html&lt;/code&gt; and &lt;code&gt;style.css&lt;/code&gt;. It can run directly in a browser without a framework, build process, or external JavaScript.&lt;/p&gt;

&lt;p&gt;This project reminded me that CSS is not only a styling language—it can also be an expressive illustration medium.&lt;/p&gt;

&lt;h2&gt;
  
  
  Source
&lt;/h2&gt;

&lt;p&gt;The complete source is available on &lt;a href="https://github.com/anilloutombam/midnight-ramen-css-art" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The project is shared under the MIT License.&lt;/p&gt;

&lt;p&gt;If you'd like to see more of what I'm building, you can explore my &lt;a href="https://dev.toPASTE_THE_ARTICLE_UTM_URL_HERE"&gt;portfolio&lt;/a&gt; or find me on &lt;a href="https://github.com/anilloutombam" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>frontendchallenge</category>
      <category>devchallenge</category>
      <category>css</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Fixing Exact Package Search Relevance in npmx</title>
      <dc:creator>L Anil Kumar Singha</dc:creator>
      <pubDate>Fri, 31 Jul 2026 10:27:09 +0000</pubDate>
      <link>https://dev.to/anilloutombam/fixing-exact-package-search-relevance-in-npmx-34c7</link>
      <guid>https://dev.to/anilloutombam/fixing-exact-package-search-relevance-in-npmx-34c7</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/bugsmash"&gt;DEV's Summer Bug Smash: Clear the Lineup&lt;/a&gt; powered by &lt;a href="https://sentry.io/" rel="noopener noreferrer"&gt;Sentry&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Overview
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://npmx.dev" rel="noopener noreferrer"&gt;npmx&lt;/a&gt; is an open-source alternative interface for exploring packages from the npm registry. It provides package details, documentation, version history, dependencies, search tools, and other information for JavaScript developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug Fix or Performance Improvement
&lt;/h2&gt;

&lt;p&gt;I worked on &lt;a href="https://github.com/npmx-dev/npmx.dev/issues/2978" rel="noopener noreferrer"&gt;issue #2978&lt;/a&gt;, which was reported by another contributor.&lt;/p&gt;

&lt;p&gt;When Algolia was selected as the search provider, the page displayed “Relevance” as the active sorting option. However, an exact package-name match did not always appear first.&lt;/p&gt;

&lt;p&gt;For example, searching for &lt;code&gt;napkin&lt;/code&gt; could show other packages above the exact match. Switching to “Downloads/wk” and then back to “Relevance” changed the results and moved &lt;code&gt;napkin&lt;/code&gt; to the top.&lt;/p&gt;

&lt;p&gt;I reproduced this behavior locally before investigating the cause.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/npmx-dev/npmx.dev/issues/2978" rel="noopener noreferrer"&gt;Issue #2978&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Pull request: &lt;a href="https://github.com/npmx-dev/npmx.dev/pull/3103" rel="noopener noreferrer"&gt;https://github.com/npmx-dev/npmx.dev/pull/3103&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Before and after
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Before
&lt;/h3&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://private-user-images.githubusercontent.com/23106365/629641010-7b90dc30-62b3-419a-9442-36a198edd8e3.mov?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3ODU0OTM3MzYsIm5iZiI6MTc4NTQ5MzQzNiwicGF0aCI6Ii8yMzEwNjM2NS82Mjk2NDEwMTAtN2I5MGRjMzAtNjJiMy00MTlhLTk0NDItMzZhMTk4ZWRkOGUzLm1vdj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjA3MzElMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwNzMxVDEwMjM1NlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWUxMzEwYjI3OGUxN2I0M2ExZGI1ZjM5MTAzMTk0OWRhYmI0NjIzMzc2M2Q4YjBkZmNhNGNkNTE1MWNjY2RmZGYmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT12aWRlbyUyRnF1aWNrdGltZSJ9.jYPPoG_cEHKfZk_oXZ1Qy1_0D2WPHbcGASouXU0PEpE" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;private-user-images.githubusercontent.com&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


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


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://private-user-images.githubusercontent.com/23106365/629641622-e73ea88e-e74c-40c6-a1a6-462760619c4b.mov?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3ODU0OTM3NTksIm5iZiI6MTc4NTQ5MzQ1OSwicGF0aCI6Ii8yMzEwNjM2NS82Mjk2NDE2MjItZTczZWE4OGUtZTc0Yy00MGM2LWExYTYtNDYyNzYwNjE5YzRiLm1vdj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjA3MzElMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwNzMxVDEwMjQxOVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTMzNzkxNmE1MTMyODRiNWIyNTg3MWIyN2MwNGI5MThlM2RlNmYzNWIzNjZhOGVhNTViZGE5OGM5NmQ0NGZlNGMmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT12aWRlbyUyRnF1aWNrdGltZSJ9.DDshiEDIyCohCupPhqxI7XlriGJAovK3XOnrHSflnRc" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;private-user-images.githubusercontent.com&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  My Improvements
&lt;/h2&gt;

&lt;p&gt;npmx already made an additional Algolia request to check whether a package with the exact searched name existed.&lt;/p&gt;

&lt;p&gt;However, this request retrieved only the package name and used the result only as an existence check. If the exact package was missing from the initial batch of results, the application knew it existed but did not have enough information to display it.&lt;/p&gt;

&lt;p&gt;I updated the exact-package request to retrieve the complete package information. When the returned package name matches the searched name, it is placed at the beginning of the results.&lt;/p&gt;

&lt;p&gt;Before adding it, the code removes any existing occurrence of the same package. This prevents duplicate results.&lt;/p&gt;

&lt;p&gt;I also added two safety checks during review:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A missing Algolia &lt;code&gt;hits&lt;/code&gt; array falls back to an empty array.&lt;/li&gt;
&lt;li&gt;A returned hit is promoted only when its name matches the requested package.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, I added a regression test that supplies a regular search result and a separate exact-package result. The test verifies that the exact package is detected and placed first.&lt;/p&gt;

&lt;p&gt;I validated the change by running the focused Nuxt tests, TypeScript checks, lint and formatting checks, and by testing the behavior manually in the local UI.&lt;/p&gt;

&lt;p&gt;After the fix, an exact package-name match appears at the top immediately when “Relevance” is selected.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>bugsmash</category>
      <category>typescript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Fixing a False “TypeScript Types Removed” Event in npmx</title>
      <dc:creator>L Anil Kumar Singha</dc:creator>
      <pubDate>Fri, 31 Jul 2026 08:43:14 +0000</pubDate>
      <link>https://dev.to/anilloutombam/fixing-a-false-typescript-types-removed-event-in-npmx-5bj6</link>
      <guid>https://dev.to/anilloutombam/fixing-a-false-typescript-types-removed-event-in-npmx-5bj6</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/bugsmash"&gt;DEV's Summer Bug Smash: Clear the Lineup&lt;/a&gt; powered by &lt;a href="https://sentry.io/" rel="noopener noreferrer"&gt;Sentry&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Overview
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://npmx.dev/" rel="noopener noreferrer"&gt;npmx&lt;/a&gt; is an open-source browser for the npm registry. It helps developers explore package metadata, versions, dependencies, documentation, and other information.&lt;/p&gt;

&lt;p&gt;I worked on &lt;a href="https://github.com/npmx-dev/npmx.dev/issues/2791" rel="noopener noreferrer"&gt;npmx issue #2791&lt;/a&gt;, which reported an incorrect event in the package-version timeline. npmx could say that a package had removed its TypeScript types even though valid declaration files were still included in the published package.&lt;/p&gt;

&lt;p&gt;My fix is available in &lt;a href="https://github.com/npmx-dev/npmx.dev/pull/3102" rel="noopener noreferrer"&gt;npmx PR #3102&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug Fix or Performance Improvement
&lt;/h2&gt;

&lt;p&gt;A package can expose TypeScript declarations explicitly through fields such as &lt;code&gt;types&lt;/code&gt; or &lt;code&gt;typings&lt;/code&gt;. It can also provide declarations implicitly by placing them beside its JavaScript entry points.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dist/index.mjs
dist/index.d.mts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;TypeScript can use &lt;code&gt;dist/index.d.mts&lt;/code&gt; even when &lt;code&gt;package.json&lt;/code&gt; does not contain a top-level &lt;code&gt;types&lt;/code&gt; field.&lt;/p&gt;

&lt;p&gt;npmx already understood this pattern on its package-analysis page. However, the timeline endpoint used &lt;code&gt;hasBuiltInTypes()&lt;/code&gt;, which only checked package metadata.&lt;/p&gt;

&lt;p&gt;This caused the two parts of npmx to disagree:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The package page correctly showed “Types included.”&lt;/li&gt;
&lt;li&gt;The timeline incorrectly showed “TypeScript types removed.”&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The fix keeps the fast metadata check as the first step. It performs the more expensive published-file analysis only for visible versions that could be part of a type-removal sequence.&lt;/p&gt;

&lt;p&gt;The latest implementation selects every untyped version that has an older typed version somewhere earlier in the package’s history:&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;const&lt;/span&gt; &lt;span class="nx"&gt;possibleTypeRemovals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;visibleVersions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hasTypes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;versionIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;allVersions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;allVersions&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;versionIndex&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;previousVersion&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;previousVersion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hasTypes&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;Checking the full sequence is important. Consider these versions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1.0.0 — explicit types field
2.0.0 — colocated .d.mts declaration
3.0.0 — colocated .d.mts declaration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An earlier version of my fix analyzed only &lt;code&gt;2.0.0&lt;/code&gt;, because it was directly beside the metadata transition. The latest version also analyzes &lt;code&gt;3.0.0&lt;/code&gt; and any other affected version in the sequence.&lt;/p&gt;

&lt;p&gt;For each candidate, the timeline fetches the package metadata and published file tree. It then reuses the project’s existing &lt;code&gt;analyzePackage()&lt;/code&gt; utility:&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;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;pkg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;typesPackage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchPackageWithTypesAndFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;packageName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;version&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;analysis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;analyzePackage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pkg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;typesPackage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;analysis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;included&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;version&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hasTypes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the additional lookup fails, the endpoint preserves the original metadata-only result instead of failing the complete timeline request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tests
&lt;/h2&gt;

&lt;p&gt;I started by running the existing test suite and confirming that all 1,716 tests passed before making changes.&lt;/p&gt;

&lt;p&gt;I then added a regression test with three package versions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;1.0.0&lt;/code&gt; declares types explicitly.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;2.0.0&lt;/code&gt; publishes &lt;code&gt;index.mjs&lt;/code&gt; and &lt;code&gt;index.d.mts&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;3.0.0&lt;/code&gt; also publishes &lt;code&gt;index.mjs&lt;/code&gt; and &lt;code&gt;index.d.mts&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The test verifies that both implicit versions are analyzed and that all three versions report TypeScript types.&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="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fetchPackageWithTypesAndFilesMock&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toHaveBeenCalledWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-pkg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fetchPackageWithTypesAndFilesMock&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toHaveBeenCalledWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-pkg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;3.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;versions&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveLength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;versions&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nx"&gt;hasTypes&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;versions&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="nx"&gt;hasTypes&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;versions&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="nx"&gt;hasTypes&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also added a genuine-removal test. In that case, the newer version publishes &lt;code&gt;index.mjs&lt;/code&gt; without a matching declaration file, so &lt;code&gt;hasTypes&lt;/code&gt; correctly remains unset.&lt;/p&gt;

&lt;p&gt;The final validation included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TypeScript type checking&lt;/li&gt;
&lt;li&gt;Repository lint checks&lt;/li&gt;
&lt;li&gt;The focused timeline test suite&lt;/li&gt;
&lt;li&gt;All 82 unit-test files&lt;/li&gt;
&lt;li&gt;The complete unit-test suite with the new regression coverage&lt;/li&gt;
&lt;li&gt;GitHub continuous-integration checks&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  My Improvements
&lt;/h2&gt;

&lt;p&gt;The final change improves the timeline in several ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It recognizes colocated &lt;code&gt;.d.mts&lt;/code&gt; declarations.&lt;/li&gt;
&lt;li&gt;It reuses the existing package-analysis implementation.&lt;/li&gt;
&lt;li&gt;It handles consecutive implicit-type versions after a metadata transition.&lt;/li&gt;
&lt;li&gt;It preserves genuine “types removed” events.&lt;/li&gt;
&lt;li&gt;It avoids failing the entire timeline when an additional file lookup is unavailable.&lt;/li&gt;
&lt;li&gt;Its tests verify array length before using optional indexed access.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;The main lesson was that package metadata does not always describe everything inside a published npm package. Removing a &lt;code&gt;types&lt;/code&gt; field does not necessarily mean that TypeScript support was removed.&lt;/p&gt;

&lt;p&gt;I also learned why regression tests should cover a sequence rather than only one transition. Testing just &lt;code&gt;1.0.0 → 2.0.0&lt;/code&gt; missed the behavior of &lt;code&gt;3.0.0&lt;/code&gt;. Extending the test revealed that every affected version after the transition needed file-aware analysis.&lt;/p&gt;

&lt;p&gt;Review feedback also improved the test quality. I replaced non-null assertions on indexed versions with an explicit length assertion and optional access.&lt;/p&gt;

&lt;p&gt;Most importantly, I reused npmx’s existing analysis logic instead of implementing another declaration-detection algorithm. This keeps the package page and timeline consistent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before and After
&lt;/h2&gt;

&lt;p&gt;Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1.0.0 — TypeScript types included
2.0.0 — TypeScript types removed
3.0.0 — TypeScript types not detected
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This could appear even when &lt;code&gt;2.0.0&lt;/code&gt; and &lt;code&gt;3.0.0&lt;/code&gt; contained valid &lt;code&gt;.d.mts&lt;/code&gt; declarations.&lt;/p&gt;

&lt;p&gt;After:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1.0.0 — TypeScript types included
2.0.0 — TypeScript types included
3.0.0 — TypeScript types included
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A release that genuinely removes both the metadata and the declaration files is still treated as a type removal.&lt;/p&gt;

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

&lt;p&gt;The implementation, tests, and review history are available in &lt;a href="https://github.com/npmx-dev/npmx.dev/pull/3102" rel="noopener noreferrer"&gt;npmx PR #3102&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>bugsmash</category>
      <category>typescript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Miso &amp; Memory: A CSS-Illustrated Ramen Landing Page for Rainy Nights</title>
      <dc:creator>L Anil Kumar Singha</dc:creator>
      <pubDate>Fri, 31 Jul 2026 05:08:24 +0000</pubDate>
      <link>https://dev.to/anilloutombam/miso-memory-a-css-illustrated-ramen-landing-page-for-rainy-nights-4i1c</link>
      <guid>https://dev.to/anilloutombam/miso-memory-a-css-illustrated-ramen-landing-page-for-rainy-nights-4i1c</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/frontend-2026-07-29"&gt;Frontend Challenge — Comfort Food Edition, Perfect Landing&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I built &lt;strong&gt;Miso &amp;amp; Memory&lt;/strong&gt;, a landing page for an imaginary late-night ramen counter.&lt;/p&gt;

&lt;p&gt;The concept is inspired by the feeling of coming home to a hot bowl after a long, rainy day: slow broth, springy noodles, warm light, and the good kind of quiet.&lt;/p&gt;

&lt;p&gt;The visual direction combines editorial typography, an earthy restaurant-inspired palette, Japanese print-inspired details, and a steaming ramen bowl illustrated with custom CSS.&lt;/p&gt;

&lt;p&gt;The landing page includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A responsive CSS-art ramen hero&lt;/li&gt;
&lt;li&gt;Animated steam and a scrolling kitchen-principles banner&lt;/li&gt;
&lt;li&gt;A curated menu of comfort bowls&lt;/li&gt;
&lt;li&gt;The story behind the imaginary restaurant&lt;/li&gt;
&lt;li&gt;An interactive “build your comfort bowl” experience&lt;/li&gt;
&lt;li&gt;Dynamic topping selection and price calculation&lt;/li&gt;
&lt;li&gt;Keyboard-friendly controls and accessible labels&lt;/li&gt;
&lt;li&gt;Visible selected and confirmation states&lt;/li&gt;
&lt;li&gt;Reduced-motion support&lt;/li&gt;
&lt;li&gt;Responsive mobile, tablet, and desktop layouts&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://miso-and-memory.nlkr50.workers.dev" rel="noopener noreferrer"&gt;Open Miso &amp;amp; Memory&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Source Code
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/anilloutombam/miso-and-memory" rel="noopener noreferrer"&gt;View the source code on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Journey
&lt;/h2&gt;

&lt;p&gt;I wanted this landing page to feel handcrafted rather than relying on conventional restaurant photography.&lt;/p&gt;

&lt;p&gt;The hero illustration is constructed from CSS shapes, borders, clipping paths, shadows, and animation. The bowl contains noodles, a jammy egg, mushrooms, greens, narutomaki, chopsticks, and rising steam.&lt;/p&gt;

&lt;p&gt;One of my favorite parts is how the illustration and interface share the same visual language. The rust-red sun becomes the primary action color, broth-inspired gold highlights selected toppings, and forest green carries through the typography and bowl outlines.&lt;/p&gt;

&lt;p&gt;I also wanted the page to be functional rather than purely decorative. Visitors can choose from three bowls, add or remove toppings, see the total update immediately, and save their selection.&lt;/p&gt;

&lt;p&gt;The interactive controls use semantic buttons, &lt;code&gt;aria-pressed&lt;/code&gt; states, and a status message when the bowl is saved. The page also respects &lt;code&gt;prefers-reduced-motion&lt;/code&gt; for visitors who prefer a calmer experience.&lt;/p&gt;

&lt;p&gt;The project is built with React, TypeScript, Vinext, Vite, and custom CSS. It is deployed publicly on Cloudflare Workers.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I Learned
&lt;/h3&gt;

&lt;p&gt;This project reminded me how much atmosphere can be created with a restrained color palette, expressive typography, and carefully composed CSS.&lt;/p&gt;

&lt;p&gt;I also learned more about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Constructing detailed illustrations from CSS primitives&lt;/li&gt;
&lt;li&gt;Balancing animation with accessibility&lt;/li&gt;
&lt;li&gt;Designing responsive editorial layouts&lt;/li&gt;
&lt;li&gt;Building keyboard-friendly selection controls&lt;/li&gt;
&lt;li&gt;Deploying a Vinext application and its static assets to Cloudflare Workers&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  AI Assistance
&lt;/h3&gt;

&lt;p&gt;I used Codex as a collaborative development tool for design exploration, implementation, accessibility improvements, troubleshooting, and deployment guidance.&lt;/p&gt;

&lt;p&gt;I reviewed and refined the project’s creative direction, interface, content, and interactions before submitting it. The social-preview image was created using an AI image-generation tool. The ramen illustration visible in the website’s hero section is implemented with CSS.&lt;/p&gt;

&lt;h3&gt;
  
  
  License
&lt;/h3&gt;

&lt;p&gt;The source code is available under the MIT License.&lt;/p&gt;

&lt;p&gt;Thanks for stopping by. Your seat at the counter is waiting. 🍜&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>frontendchallenge</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Beyond Test Automation</title>
      <dc:creator>L Anil Kumar Singha</dc:creator>
      <pubDate>Mon, 27 Jul 2026 15:32:54 +0000</pubDate>
      <link>https://dev.to/anilloutombam/beyond-test-automation-1k6l</link>
      <guid>https://dev.to/anilloutombam/beyond-test-automation-1k6l</guid>
      <description>&lt;h2&gt;
  
  
  How I Built a Scalable Release Confidence Platform with Playwright, CI/CD, and AI
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;From a manual regression process to an engineering platform that improved release confidence through deterministic automation, reusable architecture, and AI-assisted coverage analysis.&lt;/p&gt;
&lt;/blockquote&gt;




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

&lt;p&gt;Software engineering becomes harder as software becomes more successful.&lt;/p&gt;

&lt;p&gt;Early on, shipping a release is straightforward—few features, a small user base, and limited integration points. Manual verification is practical.&lt;/p&gt;

&lt;p&gt;That doesn't last.&lt;/p&gt;

&lt;p&gt;New modules ship, workflows interconnect, and changes that appear isolated begin breaking completely unrelated parts of the application.&lt;/p&gt;

&lt;p&gt;The problem stops being:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Write the feature."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It becomes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can we deploy today without breaking an existing workflow?&lt;/li&gt;
&lt;li&gt;Can we merge changes knowing critical user journeys still work?&lt;/li&gt;
&lt;li&gt;Can we tell what isn't being tested before it reaches production?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our case, the product had grown into a large enterprise application with many interconnected workflows, shipping once or twice every month. Every release depended on completing a full manual regression cycle before deployment.&lt;/p&gt;

&lt;p&gt;Regression scenarios lived in spreadsheets and were executed manually across business-critical workflows. Depending on the scope of the release, this consumed nearly an entire working day, followed by additional verification before anyone felt comfortable approving production deployment.&lt;/p&gt;

&lt;p&gt;Some releases were delayed for one reason:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Regression wasn't finished yet.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The software was ready.&lt;/p&gt;

&lt;p&gt;The pipeline was ready.&lt;/p&gt;

&lt;p&gt;Confidence wasn't.&lt;/p&gt;

&lt;p&gt;The original objective sounded simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Automate manual regression using Playwright.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It didn't stay simple.&lt;/p&gt;

&lt;p&gt;Parallel execution exposed shared-state bugs.&lt;/p&gt;

&lt;p&gt;Authentication became significantly more complex.&lt;/p&gt;

&lt;p&gt;Flaky tests quickly eroded trust.&lt;/p&gt;

&lt;p&gt;Maintaining hundreds of scenarios required the same engineering discipline as maintaining any production software system.&lt;/p&gt;

&lt;p&gt;Eventually one realization changed the direction of the project.&lt;/p&gt;

&lt;p&gt;Passing tests only answers one question.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Did the scenarios we already know about still work?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It does &lt;strong&gt;not&lt;/strong&gt; answer another equally important question.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What important user journeys are we not testing at all?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That realization transformed the effort.&lt;/p&gt;

&lt;p&gt;Instead of building a collection of Playwright scripts, we built an internal engineering platform that combined:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deterministic end-to-end automation&lt;/li&gt;
&lt;li&gt;CI/CD integration&lt;/li&gt;
&lt;li&gt;Reusable automation architecture&lt;/li&gt;
&lt;li&gt;AI-assisted coverage analysis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The AI-assisted coverage analysis agent examines existing Playwright automation, identifies missing business workflows, highlights coverage gaps, and recommends the next scenarios worth automating before those blind spots become production incidents.&lt;/p&gt;

&lt;p&gt;This isn't a Playwright tutorial.&lt;/p&gt;

&lt;p&gt;It's the engineering decisions, failures, trade-offs, and architectural lessons behind transforming manual regression from a release bottleneck into a system engineers genuinely trust.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Hidden Cost of Manual Regression
&lt;/h2&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F94a58kowf07r0dphjy93.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F94a58kowf07r0dphjy93.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We shipped one to two releases every month.&lt;/p&gt;

&lt;p&gt;Development generally finished on time.&lt;/p&gt;

&lt;p&gt;Release preparation became the bottleneck.&lt;/p&gt;

&lt;p&gt;What initially looked like a manageable checklist gradually evolved into an entire day of validation covering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Workflow management&lt;/li&gt;
&lt;li&gt;Document processing&lt;/li&gt;
&lt;li&gt;Search&lt;/li&gt;
&lt;li&gt;Approval flows&lt;/li&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;Administrative tooling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...all executed manually before every release, even when only a small feature had changed.&lt;/p&gt;

&lt;p&gt;This wasn't a discipline problem.&lt;/p&gt;

&lt;p&gt;Manual verification simply doesn't scale.&lt;/p&gt;

&lt;p&gt;Every release raised the same questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Have we tested every critical workflow?&lt;/li&gt;
&lt;li&gt;Did this change silently break another module?&lt;/li&gt;
&lt;li&gt;Are we repeatedly testing familiar paths while missing new functionality?&lt;/li&gt;
&lt;li&gt;Can we complete regression quickly enough without cutting corners?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Too often, the answer to the last question was &lt;strong&gt;no&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Releases slipped.&lt;/p&gt;

&lt;p&gt;That experience fundamentally changed how I viewed automation.&lt;/p&gt;

&lt;p&gt;Automation isn't about reducing manual effort.&lt;/p&gt;

&lt;p&gt;It's about removing release uncertainty.&lt;/p&gt;

&lt;p&gt;The real question an engineering platform should answer is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Can we confidently release this change today?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That became the design principle for everything that followed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Owning the Platform
&lt;/h2&gt;

&lt;p&gt;There was no dedicated QA or test automation engineer on the team.&lt;/p&gt;

&lt;p&gt;Alongside designing and delivering business-critical features, I took ownership of improving release quality by building the automation platform that supported them.&lt;/p&gt;

&lt;p&gt;That distinction mattered.&lt;/p&gt;

&lt;p&gt;The framework wasn't developed from the perspective of someone testing the application from the outside.&lt;/p&gt;

&lt;p&gt;It was designed with an understanding of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Business workflows&lt;/li&gt;
&lt;li&gt;System architecture&lt;/li&gt;
&lt;li&gt;Operational constraints&lt;/li&gt;
&lt;li&gt;The kinds of failures that mattered most to end users&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Building the framework, integrating it into the CI/CD pipeline, improving execution reliability, and evolving it alongside the application happened while continuing normal feature development.&lt;/p&gt;

&lt;p&gt;That experience completely changed how I viewed test automation.&lt;/p&gt;

&lt;p&gt;It wasn't a collection of Playwright scripts anymore.&lt;/p&gt;

&lt;p&gt;It became an engineering platform whose purpose was to improve release confidence through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reliable execution&lt;/li&gt;
&lt;li&gt;Reusable architecture&lt;/li&gt;
&lt;li&gt;Deterministic behavior&lt;/li&gt;
&lt;li&gt;Fast developer feedback&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every architectural decision that followed was driven by that objective.&lt;/p&gt;




&lt;h1&gt;
  
  
  Building the First Automation Framework
&lt;/h1&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0foo48naju5q2xwn3qkv.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0foo48naju5q2xwn3qkv.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Why &lt;strong&gt;Playwright&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;Its native TypeScript support, automatic waiting, built-in assertions, reliable parallel execution, and excellent debugging capabilities made it a strong foundation for building a maintainable end-to-end testing platform.&lt;/p&gt;

&lt;p&gt;One architectural constraint influenced almost every design decision.&lt;/p&gt;

&lt;p&gt;The application exposed &lt;strong&gt;no dedicated testing APIs&lt;/strong&gt; for preparing test data or bootstrapping scenarios.&lt;/p&gt;

&lt;p&gt;Automation therefore had to interact with the system exactly like a real user.&lt;/p&gt;

&lt;p&gt;That meant authentication, fixtures, state isolation, and test data management weren't conveniences.&lt;/p&gt;

&lt;p&gt;They became core responsibilities of the framework itself.&lt;/p&gt;

&lt;p&gt;Designing around those constraints ensured that automated tests validated real user journeys instead of privileged internal APIs, making the resulting feedback significantly more trustworthy.&lt;/p&gt;




&lt;h2&gt;
  
  
  Designing for Scale
&lt;/h2&gt;

&lt;p&gt;Writing Playwright tests is easy.&lt;/p&gt;

&lt;p&gt;Maintaining hundreds isn't.&lt;/p&gt;

&lt;p&gt;From the beginning, the framework separated responsibilities into clear layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configuration&lt;/li&gt;
&lt;li&gt;Test suites&lt;/li&gt;
&lt;li&gt;Page Objects&lt;/li&gt;
&lt;li&gt;Utilities&lt;/li&gt;
&lt;li&gt;Fixtures&lt;/li&gt;
&lt;li&gt;Test data&lt;/li&gt;
&lt;li&gt;Reporting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That separation meant a UI change usually affected one file instead of dozens.&lt;/p&gt;

&lt;p&gt;As the suite expanded, maintenance remained predictable instead of becoming exponentially harder.&lt;/p&gt;




&lt;h2&gt;
  
  
  Business Workflows Over Pages
&lt;/h2&gt;

&lt;p&gt;Rather than organizing tests around screens or UI components, suites were organized around complete business capabilities.&lt;/p&gt;

&lt;p&gt;That approach provided several advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Better ownership&lt;/li&gt;
&lt;li&gt;Targeted regression execution&lt;/li&gt;
&lt;li&gt;Easier failure isolation&lt;/li&gt;
&lt;li&gt;Simpler onboarding for new engineers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each suite validated an end-to-end business workflow rather than isolated button clicks or page interactions.&lt;/p&gt;

&lt;p&gt;The framework reflected how users actually interacted with the product.&lt;/p&gt;




&lt;h2&gt;
  
  
  Reusable Page Objects
&lt;/h2&gt;

&lt;p&gt;Tests interacted with business-level abstractions instead of raw selectors.&lt;/p&gt;

&lt;p&gt;Instead of repeatedly locating buttons and fields throughout the suite, implementation details remained encapsulated inside reusable Page Objects.&lt;/p&gt;

&lt;p&gt;That separation kept test cases focused on business intent.&lt;/p&gt;

&lt;p&gt;When the UI changed, updates were usually confined to a single location instead of requiring widespread modifications across hundreds of tests.&lt;/p&gt;

&lt;p&gt;The result was cleaner code, improved readability, and dramatically lower maintenance costs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Shared Fixtures
&lt;/h2&gt;

&lt;p&gt;Common setup was centralized across the framework, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authenticated browser contexts&lt;/li&gt;
&lt;li&gt;Test data preparation&lt;/li&gt;
&lt;li&gt;Browser configuration&lt;/li&gt;
&lt;li&gt;Shared fixtures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Beyond reducing boilerplate, this guaranteed that every test started from a predictable environment.&lt;/p&gt;

&lt;p&gt;As the automation suite grew, that consistency became one of the biggest contributors to execution reliability.&lt;/p&gt;




&lt;h2&gt;
  
  
  Authentication as Framework Architecture
&lt;/h2&gt;

&lt;p&gt;Authentication wasn't treated as something every individual test should perform.&lt;/p&gt;

&lt;p&gt;Instead, it became part of the framework itself.&lt;/p&gt;

&lt;p&gt;Authenticated contexts were reused where appropriate, reducing repetitive setup while improving execution speed.&lt;/p&gt;

&lt;p&gt;More importantly, separating authentication from business validation reduced instability once tests began executing concurrently.&lt;/p&gt;

&lt;p&gt;Authentication became infrastructure rather than test logic.&lt;/p&gt;




&lt;h2&gt;
  
  
  Reporting Built for Investigation
&lt;/h2&gt;

&lt;p&gt;Knowing that a test failed isn't enough.&lt;/p&gt;

&lt;p&gt;Engineers need to know &lt;strong&gt;why&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The framework generated rich debugging artifacts for every execution, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTML reports&lt;/li&gt;
&lt;li&gt;Playwright traces&lt;/li&gt;
&lt;li&gt;Execution logs&lt;/li&gt;
&lt;li&gt;Failure screenshots&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of reproducing failures locally, engineers could often identify root causes directly from the CI pipeline.&lt;/p&gt;

&lt;p&gt;Investigation became significantly faster, allowing teams to spend more time fixing problems than reproducing them.&lt;/p&gt;




&lt;p&gt;The initial results were encouraging.&lt;/p&gt;

&lt;p&gt;Manual regression effort dropped significantly.&lt;/p&gt;

&lt;p&gt;Test execution became repeatable.&lt;/p&gt;

&lt;p&gt;Releases gained a much more reliable validation process.&lt;/p&gt;

&lt;p&gt;But as the automation suite continued growing—and parallel execution increased—a completely different class of problems appeared.&lt;/p&gt;

&lt;p&gt;Interestingly, those problems weren't in the application.&lt;/p&gt;

&lt;p&gt;They were inside the automation framework itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Scaling Broke Everything
&lt;/h2&gt;

&lt;p&gt;Parallel execution changed everything.&lt;/p&gt;

&lt;p&gt;Running tests concurrently reduced execution time dramatically—but immediately exposed assumptions nobody had questioned.&lt;/p&gt;

&lt;p&gt;Tests that had always passed in sequential execution suddenly began failing intermittently.&lt;/p&gt;

&lt;p&gt;Same suite.&lt;/p&gt;

&lt;p&gt;Same code.&lt;/p&gt;

&lt;p&gt;Different outcome.&lt;/p&gt;

&lt;p&gt;That inconsistency was the first indication that the automation framework—not the application—needed architectural improvements.&lt;/p&gt;




&lt;h3&gt;
  
  
  Flaky Tests Kill Trust Fast
&lt;/h3&gt;

&lt;p&gt;Once a test can pass, fail, and then pass again without any application changes, every failure creates the same question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Is the application broken, or is the test broken?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If engineers can't answer that confidently, automation quickly loses credibility.&lt;/p&gt;

&lt;p&gt;Reliability isn't simply a nice-to-have.&lt;/p&gt;

&lt;p&gt;It's the foundation that determines whether developers trust automated regression enough to make release decisions based on it.&lt;/p&gt;




&lt;h3&gt;
  
  
  Root Cause: Shared State
&lt;/h3&gt;

&lt;p&gt;The biggest issue turned out to be shared state.&lt;/p&gt;

&lt;p&gt;Parallel workers were unintentionally interacting with common resources.&lt;/p&gt;

&lt;p&gt;Tests assumed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data created by previous executions still existed.&lt;/li&gt;
&lt;li&gt;Application state would remain unchanged throughout the suite.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both assumptions broke under concurrent execution.&lt;/p&gt;

&lt;p&gt;Instead of adding retries, the framework introduced stronger isolation between test runs so each scenario could execute independently.&lt;/p&gt;

&lt;p&gt;Isolation—not retries—became the long-term solution.&lt;/p&gt;




&lt;h3&gt;
  
  
  Authentication Under Load
&lt;/h3&gt;

&lt;p&gt;Authentication became another scaling challenge.&lt;/p&gt;

&lt;p&gt;Initially, authenticated sessions were reused across multiple workers.&lt;/p&gt;

&lt;p&gt;That worked until concurrency increased.&lt;/p&gt;

&lt;p&gt;Multiple workers sharing authentication contexts introduced unpredictable session behavior that appeared completely random during execution.&lt;/p&gt;

&lt;p&gt;The solution wasn't adding more login steps.&lt;/p&gt;

&lt;p&gt;It was treating authentication as framework architecture rather than business logic.&lt;/p&gt;

&lt;p&gt;Authentication became infrastructure.&lt;/p&gt;

&lt;p&gt;Business validation remained inside the tests.&lt;/p&gt;

&lt;p&gt;That separation improved both execution speed and reliability.&lt;/p&gt;




&lt;h3&gt;
  
  
  Timeouts Were Symptoms, Not Problems
&lt;/h3&gt;

&lt;p&gt;Increasing timeout values is one of the easiest ways to make unstable tests appear reliable.&lt;/p&gt;

&lt;p&gt;It's also one of the easiest ways to hide real problems.&lt;/p&gt;

&lt;p&gt;Whenever a timeout occurred, the first question was never:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Should we increase the timeout?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead, the investigation focused on the underlying cause.&lt;/p&gt;

&lt;p&gt;Was the application genuinely slow?&lt;/p&gt;

&lt;p&gt;Was a selector unstable?&lt;/p&gt;

&lt;p&gt;Was another worker interfering?&lt;/p&gt;

&lt;p&gt;Was the test depending on stale data?&lt;/p&gt;

&lt;p&gt;Fixing those issues produced a far more reliable framework than simply increasing timeout values.&lt;/p&gt;




&lt;h3&gt;
  
  
  Scaling Without Guesswork
&lt;/h3&gt;

&lt;p&gt;As the suite continued growing, another pattern emerged.&lt;/p&gt;

&lt;p&gt;Increasing the number of parallel workers increased contention on shared backend resources—particularly database connection pools.&lt;/p&gt;

&lt;p&gt;Interestingly, latency didn't grow linearly.&lt;/p&gt;

&lt;p&gt;Doubling worker count didn't double execution time.&lt;/p&gt;

&lt;p&gt;Instead of relying on arbitrary timeout values, timeout budgets were tuned using observed execution characteristics.&lt;/p&gt;

&lt;p&gt;The objective wasn't making tests pass.&lt;/p&gt;

&lt;p&gt;It was ensuring failures remained meaningful.&lt;/p&gt;

&lt;p&gt;That distinction changed how the framework evolved.&lt;/p&gt;

&lt;p&gt;Engineering effort shifted from masking failures to eliminating the reasons they occurred.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Retries Weren't the Answer
&lt;/h2&gt;

&lt;p&gt;Many automation frameworks rely on retries.&lt;/p&gt;

&lt;p&gt;If a test fails, run it again.&lt;/p&gt;

&lt;p&gt;That approach can improve pass rates, but it often hides the real problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Race conditions&lt;/li&gt;
&lt;li&gt;Shared state&lt;/li&gt;
&lt;li&gt;Timing assumptions&lt;/li&gt;
&lt;li&gt;Unstable selectors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A green pipeline doesn't necessarily mean a reliable test suite.&lt;/p&gt;

&lt;p&gt;It may simply mean the framework retried enough times to hide the instability.&lt;/p&gt;

&lt;p&gt;Instead of increasing retries, the objective was to eliminate the reasons retries were needed in the first place.&lt;/p&gt;

&lt;p&gt;That required architectural changes—not additional assertions.&lt;/p&gt;

&lt;p&gt;The framework was redesigned for deterministic parallel execution, introducing stronger isolation between concurrent test runs and a clearer separation between shared setup and business validation.&lt;/p&gt;

&lt;p&gt;Authentication, fixtures, and test state were managed so that one test could no longer influence another, even under heavy concurrency.&lt;/p&gt;

&lt;p&gt;As execution became deterministic, retries gradually stopped providing meaningful value.&lt;/p&gt;

&lt;p&gt;Instead of masking intermittent failures, the framework consistently surfaced genuine issues, allowing engineers to fix root causes rather than chase flaky tests.&lt;/p&gt;

&lt;p&gt;The broader lesson was clear.&lt;/p&gt;

&lt;p&gt;Large-scale automation problems are usually software engineering problems.&lt;/p&gt;

&lt;p&gt;Solving them required architecture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clear isolation boundaries&lt;/li&gt;
&lt;li&gt;Reusable abstractions&lt;/li&gt;
&lt;li&gt;Reliable fixture management&lt;/li&gt;
&lt;li&gt;Predictable execution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;—not simply writing more assertions.&lt;/p&gt;




&lt;h2&gt;
  
  
  From Stability to Coverage: AI-Assisted Coverage Analysis
&lt;/h2&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5oceo3qwg1u8ekvreig2.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5oceo3qwg1u8ekvreig2.png" alt=" " width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even after building a fast and reliable automation platform, one question remained unanswered.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;How do we know which important workflows aren't being tested at all?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Execution quality had improved.&lt;/p&gt;

&lt;p&gt;Coverage quality was still largely a guess.&lt;/p&gt;

&lt;p&gt;That realization led to building an AI-assisted coverage analysis agent.&lt;/p&gt;

&lt;p&gt;Instead of simply answering:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Did the tests pass?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;the platform could now answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"What are we still not testing?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The objective wasn't generating tests automatically.&lt;/p&gt;

&lt;p&gt;The objective was helping engineers make better decisions about where automation effort should go next.&lt;/p&gt;




&lt;h3&gt;
  
  
  Design Principles
&lt;/h3&gt;

&lt;h4&gt;
  
  
  AI Assists. Engineers Decide.
&lt;/h4&gt;

&lt;p&gt;The agent doesn't generate automation autonomously.&lt;/p&gt;

&lt;p&gt;Instead, it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Identifies blind spots&lt;/li&gt;
&lt;li&gt;Detects missing business workflows&lt;/li&gt;
&lt;li&gt;Suggests high-value scenarios&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Engineers remain responsible for reviewing and implementing those recommendations.&lt;/p&gt;

&lt;p&gt;Decision-making stays transparent and accountable.&lt;/p&gt;




&lt;h4&gt;
  
  
  Business Workflows Over UI Elements
&lt;/h4&gt;

&lt;p&gt;Counting pages, buttons, or components says very little about release confidence.&lt;/p&gt;

&lt;p&gt;Instead, the analysis focuses on complete business journeys.&lt;/p&gt;

&lt;p&gt;The objective is measuring workflow coverage—not interface coverage.&lt;/p&gt;

&lt;p&gt;That ensures the scenarios users actually depend on are represented inside the automated suite.&lt;/p&gt;




&lt;h4&gt;
  
  
  Explainable, Not Opaque
&lt;/h4&gt;

&lt;p&gt;Every coverage classification—&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Covered&lt;/li&gt;
&lt;li&gt;Partially Covered&lt;/li&gt;
&lt;li&gt;Not Covered&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;can be traced back to observable application behavior and existing Playwright automation.&lt;/p&gt;

&lt;p&gt;Nothing is hidden behind a black-box score.&lt;/p&gt;

&lt;p&gt;Engineers can validate every recommendation before acting on it.&lt;/p&gt;




&lt;h4&gt;
  
  
  Actionable Over Informational
&lt;/h4&gt;

&lt;p&gt;Reports don't simply describe the current state.&lt;/p&gt;

&lt;p&gt;They prioritize uncovered workflows by estimated business impact and recommend the next scenarios worth automating.&lt;/p&gt;

&lt;p&gt;The goal is reducing engineering decision fatigue—not generating another dashboard.&lt;/p&gt;




&lt;h4&gt;
  
  
  Deterministic Output
&lt;/h4&gt;

&lt;p&gt;Running the analysis twice against the same application and the same automation suite should produce identical conclusions.&lt;/p&gt;

&lt;p&gt;Recommendations should change only because the application changes—not because the analysis is inconsistent.&lt;/p&gt;




&lt;h4&gt;
  
  
  Continuous, Not One-Time
&lt;/h4&gt;

&lt;p&gt;Coverage isn't something you "finish."&lt;/p&gt;

&lt;p&gt;Every feature changes the application's risk profile.&lt;/p&gt;

&lt;p&gt;The question evolves from:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Have we completed automation?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"What should we automate next to reduce release risk?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Current Limitations
&lt;/h3&gt;

&lt;p&gt;The coverage analysis agent deliberately has a narrow responsibility.&lt;/p&gt;

&lt;p&gt;It does &lt;strong&gt;not&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Execute Playwright tests&lt;/li&gt;
&lt;li&gt;Determine whether application behavior is correct&lt;/li&gt;
&lt;li&gt;Replace engineering judgment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead, it analyzes the relationship between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expected business workflows&lt;/li&gt;
&lt;li&gt;Existing Playwright automation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Its effectiveness depends on well-structured Playwright projects, meaningful test names, reusable page objects, and clearly defined business workflows.&lt;/p&gt;

&lt;p&gt;It's a decision-support system—not a quality certification.&lt;/p&gt;

&lt;p&gt;For business-critical functionality, human review remains essential.&lt;/p&gt;

&lt;h2&gt;
  
  
  Continuous Quality in CI/CD
&lt;/h2&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flrxkmttdi878gvqdfh2t.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flrxkmttdi878gvqdfh2t.png" alt=" " width="800" height="254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The framework delivered its greatest value once it stopped depending on someone remembering to run it manually.&lt;/p&gt;

&lt;p&gt;Instead, it became part of the delivery pipeline itself.&lt;/p&gt;

&lt;p&gt;Integrated into GitLab CI/CD, every meaningful change executed the same deterministic regression suite before moving forward.&lt;/p&gt;

&lt;p&gt;The biggest mindset shift wasn't technical.&lt;/p&gt;

&lt;p&gt;It was moving from asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Has regression been run?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;to asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Did regression pass?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That seemingly small change fundamentally altered how release decisions were made.&lt;/p&gt;

&lt;p&gt;The pipeline provided:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Standardized execution&lt;/strong&gt; — Every run used the same browser, configuration, assertions, and reporting, eliminating "works on my machine" inconsistencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parallel execution&lt;/strong&gt; — Runtime remained practical even as the suite grew, without sacrificing isolation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fail-fast behavior&lt;/strong&gt; — Critical failures stopped the pipeline early instead of wasting time executing an already-failed build.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rich debugging artifacts&lt;/strong&gt; — HTML reports, Playwright traces, logs, and screenshots made most failures understandable directly from CI without reproducing them locally.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Regression stopped being a checklist.&lt;/p&gt;

&lt;p&gt;It became a deployment gate alongside build validation and code quality.&lt;/p&gt;

&lt;p&gt;Passing the pipeline no longer meant:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"The project compiles."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It meant:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Critical business workflows continue to work."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Counterintuitively, adding more automation actually accelerated delivery.&lt;/p&gt;

&lt;p&gt;Less manual verification.&lt;/p&gt;

&lt;p&gt;More predictable releases.&lt;/p&gt;

&lt;p&gt;Release decisions backed by evidence instead of intuition.&lt;/p&gt;




&lt;h2&gt;
  
  
  Measuring the Impact
&lt;/h2&gt;

&lt;p&gt;Several hundred end-to-end scenarios that previously required nearly an entire working day of manual validation now execute automatically within minutes as part of every meaningful CI run.&lt;/p&gt;

&lt;p&gt;The impact wasn't simply faster execution.&lt;/p&gt;

&lt;p&gt;It fundamentally changed how the team approached release quality.&lt;/p&gt;

&lt;h3&gt;
  
  
  Repeatable Outcomes
&lt;/h3&gt;

&lt;p&gt;Regression results no longer depended on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Who executed the tests&lt;/li&gt;
&lt;li&gt;How much time remained before release&lt;/li&gt;
&lt;li&gt;Individual interpretation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every execution followed the same deterministic process.&lt;/p&gt;




&lt;h3&gt;
  
  
  Faster Investigation
&lt;/h3&gt;

&lt;p&gt;Rich debugging artifacts—including Playwright traces, execution reports, logs, and screenshots—made it possible to understand most failures directly from the CI pipeline.&lt;/p&gt;

&lt;p&gt;Instead of spending time reproducing issues locally, engineers could begin fixing problems immediately.&lt;/p&gt;




&lt;h3&gt;
  
  
  Measurable Confidence
&lt;/h3&gt;

&lt;p&gt;Release readiness was supported by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Validated business workflows&lt;/li&gt;
&lt;li&gt;Reproducible failures&lt;/li&gt;
&lt;li&gt;Reviewable reports&lt;/li&gt;
&lt;li&gt;Coverage analysis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Confidence became measurable instead of subjective.&lt;/p&gt;




&lt;h3&gt;
  
  
  From Reactive to Proactive Quality
&lt;/h3&gt;

&lt;p&gt;Instead of repeatedly asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Why did this break?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;the conversation increasingly became:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"What important workflows are still missing from automation?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That shift transformed automation from a validation activity into a continuous engineering practice.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;p&gt;Building this platform changed how I think about software engineering—not just test automation.&lt;/p&gt;

&lt;p&gt;Several lessons continue to influence how I design systems today.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Automation Is Software
&lt;/h3&gt;

&lt;p&gt;Automation deserves the same engineering discipline as production code.&lt;/p&gt;

&lt;p&gt;It needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modular architecture&lt;/li&gt;
&lt;li&gt;Code reviews&lt;/li&gt;
&lt;li&gt;Reusable abstractions&lt;/li&gt;
&lt;li&gt;Continuous refactoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;—not simply more scripts.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Reliability Beats Quantity
&lt;/h3&gt;

&lt;p&gt;A small automation suite that engineers trust creates more value than hundreds of unreliable tests.&lt;/p&gt;

&lt;p&gt;Determinism matters more than raw test count.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Fast Feedback Changes Engineering Behavior
&lt;/h3&gt;

&lt;p&gt;Slow regression gradually gets ignored.&lt;/p&gt;

&lt;p&gt;Fast, deterministic regression integrated into CI becomes part of every engineering decision.&lt;/p&gt;

&lt;p&gt;The faster feedback arrives, the earlier problems are discovered.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Coverage Matters More Than Test Count
&lt;/h3&gt;

&lt;p&gt;Hundreds of green tests don't necessarily mean important workflows are protected.&lt;/p&gt;

&lt;p&gt;Understanding what &lt;strong&gt;isn't&lt;/strong&gt; covered is often more valuable than knowing what already is.&lt;/p&gt;

&lt;p&gt;That's exactly the problem the AI-assisted coverage analysis agent was designed to solve.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. AI Should Augment Engineering Judgment
&lt;/h3&gt;

&lt;p&gt;The goal wasn't replacing engineers.&lt;/p&gt;

&lt;p&gt;The goal was accelerating analysis, surfacing blind spots, and helping teams prioritize automation work more effectively.&lt;/p&gt;

&lt;p&gt;Engineering decisions remained human.&lt;/p&gt;




&lt;h3&gt;
  
  
  6. Quality Is Continuous
&lt;/h3&gt;

&lt;p&gt;Quality isn't something added before a release.&lt;/p&gt;

&lt;p&gt;Every feature changes the application's risk surface.&lt;/p&gt;

&lt;p&gt;Automation must evolve continuously alongside the software itself.&lt;/p&gt;




&lt;h3&gt;
  
  
  7. Confidence Is the Real Deliverable
&lt;/h3&gt;

&lt;p&gt;The most valuable outcome wasn't:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Playwright&lt;/li&gt;
&lt;li&gt;CI/CD integration&lt;/li&gt;
&lt;li&gt;Parallel execution&lt;/li&gt;
&lt;li&gt;Reporting&lt;/li&gt;
&lt;li&gt;AI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are implementation details.&lt;/p&gt;

&lt;p&gt;The real deliverable was enabling engineers to make release decisions based on evidence instead of intuition.&lt;/p&gt;




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

&lt;p&gt;The original goal was straightforward.&lt;/p&gt;

&lt;p&gt;Automate manual regression.&lt;/p&gt;

&lt;p&gt;What ultimately emerged was something much broader.&lt;/p&gt;

&lt;p&gt;It demonstrated that quality engineering is fundamentally a software engineering discipline—not a separate track.&lt;/p&gt;

&lt;p&gt;This wasn't work performed instead of building the product.&lt;/p&gt;

&lt;p&gt;It came directly from building it.&lt;/p&gt;

&lt;p&gt;Understanding the application's architecture, business workflows, and operational constraints made it possible to design an automation platform that remained reliable, maintainable, and scalable as the product evolved.&lt;/p&gt;

&lt;p&gt;The platform combined:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deterministic automation&lt;/li&gt;
&lt;li&gt;Parallel execution&lt;/li&gt;
&lt;li&gt;Reusable architecture&lt;/li&gt;
&lt;li&gt;CI/CD integration&lt;/li&gt;
&lt;li&gt;Rich debugging artifacts&lt;/li&gt;
&lt;li&gt;AI-assisted coverage analysis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the most important outcome wasn't the technology.&lt;/p&gt;

&lt;p&gt;It was changing how release decisions were made.&lt;/p&gt;

&lt;p&gt;Replacing intuition with evidence.&lt;/p&gt;

&lt;p&gt;Automation tells you what you already know still works.&lt;/p&gt;

&lt;p&gt;Coverage analysis tells you what you've overlooked.&lt;/p&gt;

&lt;p&gt;Both are necessary.&lt;/p&gt;

&lt;p&gt;Together, they provide a stronger foundation for release confidence than either could alone.&lt;/p&gt;




&lt;p&gt;Looking ahead, there are still opportunities to push quality engineering further:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Risk-based regression selection&lt;/li&gt;
&lt;li&gt;Historical coverage trend analysis&lt;/li&gt;
&lt;li&gt;Pull request–level coverage impact reports&lt;/li&gt;
&lt;li&gt;AI-assisted test maintenance&lt;/li&gt;
&lt;li&gt;Flaky-test detection&lt;/li&gt;
&lt;li&gt;Visual regression&lt;/li&gt;
&lt;li&gt;Requirement-to-test traceability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are areas I'd like to continue exploring as software systems—and the expectations around software quality—continue to evolve.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;If you've built something similar, or approached release confidence differently, I'd genuinely love to hear about it. Let's connect and discuss.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>playwright</category>
      <category>softwareengineering</category>
      <category>typescript</category>
    </item>
    <item>
      <title>How to add watermark on an image in Laravel 5.8 Step by Step</title>
      <dc:creator>L Anil Kumar Singha</dc:creator>
      <pubDate>Tue, 04 Aug 2020 06:46:41 +0000</pubDate>
      <link>https://dev.to/anilloutombam/how-to-add-watermark-on-an-image-in-laravel-5-8-step-by-step-5acd</link>
      <guid>https://dev.to/anilloutombam/how-to-add-watermark-on-an-image-in-laravel-5-8-step-by-step-5acd</guid>
      <description>&lt;p&gt;In this blog post, we will learn, how to add watermark to an image in Laravel 5.8 application, to add watermark to images we will use the intervention image composer package in Laravel 5.8. we can add images or text as a watermark on the image in Laravel. For more docs, you can follow them.&lt;br&gt;
&lt;a href="http://image.intervention.io/" rel="noopener noreferrer"&gt;Intervention Image&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To make a watermark on an image. we will install intervention/image package and then we will create one simple route to adding image watermark in the Laravel app. so let’s follow the below step to add image watermark in Laravel 5.8.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step:1 Install intervention/image Package.
&lt;/h2&gt;

&lt;p&gt;In the first step, I install an intervention/image composer package for adding watermark to the image in Laravel 5.8. to install a package using the following command.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;composer require intervention/image&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
After installation, we need to set providers and alias, to do that we need to follow some steps… go to your project and search.&lt;/p&gt;
&lt;h3&gt;
  
  
  config/app.php
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;providers&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="nc"&gt;Intervention\Image\ImageServiceProvider&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;aliases&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
 &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nc"&gt;Image&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Intervention\Image\Facades\Image&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Step:2 Add Watermark to image
&lt;/h3&gt;

&lt;p&gt;Here, I created a controller(you can use a simple route) to add a watermark to the image. so you need to add two images on your public “images” folder for testing purposes.&lt;/p&gt;

&lt;p&gt;Here I use two images one for the main image and a second image for watermark so I have a &lt;strong&gt;main.png&lt;/strong&gt; and &lt;strong&gt;watermark.png&lt;/strong&gt; image on your images folder for demo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;addWatermark&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
   &lt;span class="nv"&gt;$img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Image&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;public_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'images/main.png'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;    
   &lt;span class="nv"&gt;$img&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;public_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'watermark.png'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="s1"&gt;'bottom-right'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
   &lt;span class="nv"&gt;$img&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;save&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;So here we completed tutorials on How to Add Watermark on an Images in Laravel 5.8 step by step.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>TIPS AND TRICKS FOR JAVASCRIPT BEGINNERS</title>
      <dc:creator>L Anil Kumar Singha</dc:creator>
      <pubDate>Tue, 14 Jul 2020 08:26:27 +0000</pubDate>
      <link>https://dev.to/anilloutombam/tips-and-tricks-for-javascript-beginners-565b</link>
      <guid>https://dev.to/anilloutombam/tips-and-tricks-for-javascript-beginners-565b</guid>
      <description>&lt;p&gt;In this article, I’ll share a set of JavaScript tips, tricks, and best practices that should be known by all JavaScript developers regardless of their browser/engine or the SSJS (Server Side JavaScript) interpreter.&lt;/p&gt;

&lt;h3&gt;
  
  
  Covered Topics are :-
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. References&lt;/strong&gt;,&lt;br&gt;
&lt;strong&gt;2. Objects&lt;/strong&gt;,&lt;br&gt;
&lt;strong&gt;3. Arrays&lt;/strong&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;1.1 Use &lt;code&gt;const&lt;/code&gt; for all of your references; avoid using &lt;code&gt;var&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Why? This ensures that you can’t reassign your references, which can lead to bugs and difficult to comprehend code.&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// bad way to write&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// this is the good way to write avoid using var&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;1.2 If you must reassign references, use &lt;code&gt;let&lt;/code&gt; instead of &lt;code&gt;var&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Why? &lt;code&gt;let&lt;/code&gt; is block-scoped rather than function-scoped like &lt;code&gt;var&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// bad&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// good, use the let.&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;1.3 Note that both &lt;code&gt;let&lt;/code&gt; and &lt;code&gt;const&lt;/code&gt; are &lt;strong&gt;block-scoped&lt;/strong&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// const and let only exist in the blocks they are defined in.&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;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;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ReferenceError&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;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ReferenceError&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Objects
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;2.1 Use the literal syntax for object creation.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// bad&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// good&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;2.2 Use computed property names when creating objects with dynamic property names.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Why? They allow you to define all the properties of an object in one place.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&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;getKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`a key named &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// bad&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Tony Stark&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;obj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;getKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;enabled&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// good&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Tony Stark&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;getKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;enabled&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)]:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;2.3 Use object method shorthand.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// bad&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;atom&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;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="na"&gt;addValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;atom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// good&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;atom&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;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="nf"&gt;addValue&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="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;atom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;2.4 Use property value shorthand.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Why? It is shorter and descriptive.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&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;tonyStark&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Tony Stark&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// bad&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;tonyStark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tonyStark&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// good&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;tonyStark&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;2.5 Group your shorthand properties at the beginning of your object declaration.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Why? It’s easier to tell which properties are using the shorthand.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&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;anakinSkywalker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Anakin Skywalker&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;lukeSkywalker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Luke Skywalker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// bad&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;episodeOne&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="na"&gt;twoJediWalkIntoACantina&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="nx"&gt;lukeSkywalker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;episodeThree&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="na"&gt;mayTheFourth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;anakinSkywalker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// good&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;lukeSkywalker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;anakinSkywalker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;episodeOne&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="na"&gt;twoJediWalkIntoACantina&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="na"&gt;episodeThree&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="na"&gt;mayTheFourth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;2.6 Only quote properties that are invalid identifiers.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Why? In general, we consider it subjectively easier to read. It improves syntax highlighting and is also more easily optimized by many JS engines.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// bad&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bad&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;'&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-blah&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// good&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;good&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;foo&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="na"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-blah&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;2.7 Do not call &lt;code&gt;Object.prototype&lt;/code&gt; methods directly, such as &lt;code&gt;hasOwnProperty&lt;/code&gt;, &lt;code&gt;propertyIsEnumerable&lt;/code&gt;, and &lt;code&gt;isPrototypeOf&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Why? These methods may be shadowed by properties on the object in question - consider &lt;code&gt;{ hasOwnProperty: false }&lt;/code&gt; - or, the object may be a null object &lt;code&gt;(Object.create(null))&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// bad&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;object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasOwnProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// good&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="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hasOwnProperty&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// best&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;has&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hasOwnProperty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// cache the lookup once, in module scope.&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;has&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="cm"&gt;/* or */&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;has&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;has&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// https://www.npmjs.com/package/has&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="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;2.8  Prefer the object spread operator over &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign" rel="noopener noreferrer"&gt;Object.assign&lt;/a&gt; to shallow-copy objects. Use the object rest operator to get a new object with certain properties omitted.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// very bad&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;original&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&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="na"&gt;b&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;copy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;original&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// this mutates `original` ಠ_ಠ&lt;/span&gt;
&lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="nx"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// so does this&lt;/span&gt;

&lt;span class="c1"&gt;// bad&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;original&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&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="na"&gt;b&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;copy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="nx"&gt;original&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// copy =&amp;gt; { a: 1, b: 2, c: 3 }&lt;/span&gt;

&lt;span class="c1"&gt;// good&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;original&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&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="na"&gt;b&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;copy&lt;/span&gt; &lt;span class="o"&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;original&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;// copy =&amp;gt; { a: 1, b: 2, c: 3 }&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;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;noA&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// noA =&amp;gt; { b: 2, c: 3 }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Arrays
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;3.1 Use the literal syntax for array creation.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// bad&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// good&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;3.2 Use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push" rel="noopener noreferrer"&gt;Array#Push&lt;/a&gt; instead of direct assignment to add items to an array.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;someStack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="c1"&gt;// bad&lt;/span&gt;
&lt;span class="nx"&gt;someStack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;someStack&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="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;abracadabra&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// good&lt;/span&gt;
&lt;span class="nx"&gt;someStack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;abracadabra&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;ul&gt;
&lt;li&gt;3.3 Use array spreads &lt;code&gt;...&lt;/code&gt; to copy arrays.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// bad&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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;itemsCopy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&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="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;itemsCopy&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// good&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;itemsCopy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;3.4 To convert an iterable object to an array, use spreads &lt;code&gt;...&lt;/code&gt; instead of &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from" rel="noopener noreferrer"&gt;Array.from&lt;/a&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="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="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&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="c1"&gt;// good&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&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="c1"&gt;// best&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nodes&lt;/span&gt; &lt;span class="o"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;3.5 Use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from" rel="noopener noreferrer"&gt;Array.from&lt;/a&gt; for converting an array-like object to an array.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arrLike&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="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="mi"&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;bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;baz&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// bad&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arrLike&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// good&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arrLike&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;3.6 Use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from" rel="noopener noreferrer"&gt;Array.from&lt;/a&gt; instead of spread &lt;code&gt;...&lt;/code&gt; for mapping over iterables, because it avoids creating an intermediate array.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// bad&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;baz&lt;/span&gt; &lt;span class="o"&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="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// good&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;baz&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&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="nx"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;3.7 Use return statements in array method callbacks. It’s ok to omit the return if the function body consists of a single statement returning an expression without side effects.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// good&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// good&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// bad - no returned value means `acc` becomes undefined after the first iteration&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;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]].&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;flatten&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// good&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;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]].&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;flatten&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// bad&lt;/span&gt;
&lt;span class="nx"&gt;inbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;author&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subject&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Mockingbird&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;author&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Harper Lee&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="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// good&lt;/span&gt;
&lt;span class="nx"&gt;inbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;author&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subject&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Mockingbird&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;author&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Harper Lee&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="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;3.8 Use line breaks after open and before close array brackets if an array has multiple lines.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// bad&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;objectInArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;numberInArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// good&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;objectInArray&lt;/span&gt; &lt;span class="o"&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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;numberInArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;Alright, that were useful JavaScript tips and tricks. I hope you've learned something new and you can go ahead to improve your code. If you sight anything wrong just let me know! &lt;br&gt;
Thanks for reading.&lt;/p&gt;

&lt;p&gt;If you liked the post, You can follow up here for more.&lt;br&gt;
&lt;a href="https://github.com/anilloutombam" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;br&gt;
&lt;a href="https://medium.com/@anilloutombam" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;.&lt;br&gt;
&lt;a href="https://www.hackerrank.com/nlkr50" rel="noopener noreferrer"&gt;HackerRank&lt;/a&gt;.&lt;br&gt;
&lt;a href="https://www.linkedin.com/in/anil-loutombam/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>beginners</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
