<?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: Gaurav Behere</title>
    <description>The latest articles on DEV Community by Gaurav Behere (@gauravbehere).</description>
    <link>https://dev.to/gauravbehere</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F430717%2F23fe06fa-c988-4a35-a8e8-5f9dd134d28c.jpg</url>
      <title>DEV Community: Gaurav Behere</title>
      <link>https://dev.to/gauravbehere</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gauravbehere"/>
    <language>en</language>
    <item>
      <title>The I/O ’26 Moment That Actually Stuck With Me</title>
      <dc:creator>Gaurav Behere</dc:creator>
      <pubDate>Sat, 23 May 2026 16:41:17 +0000</pubDate>
      <link>https://dev.to/gauravbehere/the-io-26-moment-that-actually-stuck-with-me-1cbf</link>
      <guid>https://dev.to/gauravbehere/the-io-26-moment-that-actually-stuck-with-me-1cbf</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/google-io-writing-2026-05-19"&gt;Google I/O Writing Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Watching the I/O ’26 keynotes and developer sessions, it was easy to get distracted by the big narratives about “agentic workflows” and new capabilities in Gemini. But the part that lodged in my brain wasn’t a new model—it was the moment when Google effectively wired an AI coding agent directly into Chrome DevTools and handed it a set of opinionated web skills called &lt;strong&gt;Modern Web Guidance&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Taken together, those two pieces make a simple but important promise: instead of just asking an agent to spit out React components and hoping they run, you can now let it see, audit, and debug a real browser session, guided by a curated checklist of what “&lt;strong&gt;good modern web&lt;/strong&gt;” looks like. That’s a very different posture from “AI as autocomplete,” and it’s the kind of tooling that can quietly change how web teams actually ship code.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Google Actually Shipped
&lt;/h2&gt;

&lt;p&gt;In the Developer Keynote recap, Google framed this era as “agentic workflows,” and introduced Antigravity as the platform where agents handle the heavy lifting while you stay focused on design and intent. Within that story, Chrome’s announcements were about giving those agents real, first‑class tools rather than treating the browser as an opaque black box.&lt;/p&gt;

&lt;p&gt;Two pieces are central here. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, Chrome DevTools for agents: a Model Context Protocol (MCP) server and CLI that let coding agents like Gemini CLI, Antigravity, Cursor, Claude Code and others connect directly to a live Chrome instance to run audits, emulate devices, and inspect runtime behavior. &lt;/li&gt;
&lt;li&gt;Second, Modern Web Guidance: an “evergreen, expert‑vetted” skill package that encodes Google’s own best practices for accessibility, performance, and security into reusable instructions that can be injected into your agent’s context.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Modern Web Guidance ships as an installable skill (via a dedicated CLI, GitHub repo, or integration with agent platforms), while DevTools for agents provides the bridge between those skills and the actual browser runtime where your app lives. In other words, one tells the agent what “good” looks like on the web; the other lets it verify whether your app matches that definition in a real environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agents That Can Actually See the Browser
&lt;/h2&gt;

&lt;p&gt;If you’ve used AI coding assistants before, you know the core limitation: &lt;strong&gt;they generate a lot of plausible code, but they typically can’t watch that code run in a real browser&lt;/strong&gt;. They hallucinate fixes based on static snippets and log fragments, with no real way to test assumptions against a live UI or network waterfall.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Chrome DevTools for agents attacks that gap directly&lt;/strong&gt;. Google’s documentation shows three key integration surfaces: an MCP server that connects LLMs to DevTools, a CLI for token‑efficient scripted interactions, and a set of “agent skills” that teach agents how and when to use the available tools. Once wired up, the agent can do things that were previously strictly human territory: run Lighthouse audits for accessibility and SEO, emulate different devices and throttled networks, interact with forms, and even debug Chrome extensions.&lt;/p&gt;

&lt;p&gt;Critically, this isn’t a synthetic sandbox. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Agents can now connect to your active Chrome session, which means you can hand an authenticated dashboard or an internal tool to the agent and let it investigate issues using your real login state. That’s a big shift compared to the usual pattern of pasting screenshots and hoping the model guesses what’s wrong.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Modern Web Guidance: Opinionated Skills, Not Just Raw Power
&lt;/h2&gt;

&lt;p&gt;On its own, giving an agent access to DevTools could just mean it runs random audits and drowns you in output. Modern Web Guidance is the other half of the story: it’s a curated skill set that tells the agent how to build and repair web experiences in a way that aligns with Chrome’s view of “modern.”&lt;/p&gt;

&lt;p&gt;Modern Web Guidance is a set of “evergreen and expert‑vetted skills” that cover over 100 web development use cases, focused on accessibility, performance, and security. You install it via a dedicated CLI (&lt;code&gt;npx modern-web-guidance@latest install&lt;/code&gt;), through GitHub, or by using agent‑skill integrations in platforms like Antigravity, Vercel’s Agent Skills, Claude Code, and Copilot CLI.&lt;/p&gt;

&lt;p&gt;The effect is that your agent isn’t just generating whatever HTML and JavaScript seems most likely; it’s being steered by explicit patterns that consider Baseline support, fallbacks, and contemporary best practices. When you combine that with a live DevTools connection, you get a loop where the agent can run an audit, compare the findings against those skills, and then propose concrete, standards‑aligned code changes instead of generic advice.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Quiet Reframing of Web Work
&lt;/h2&gt;

&lt;p&gt;The obvious reading of these announcements is “better AI tools for debugging,” but I think there’s a quieter reframing happening underneath. In the I/O schedule and recaps, Google keeps talking about “agent‑ready web applications” and “agentic workflows,” which is another way of saying they expect AI agents to become first‑class participants in the dev loop, not just helpers that comment on diffs.&lt;/p&gt;

&lt;p&gt;When your agent can navigate your app, throttle the network, simulate geolocation, and run Lighthouse, it stops being a code suggester and starts acting more like a junior engineer who can run checks, reproduce bugs, and report back with structured findings. Modern Web Guidance then functions like the senior engineer’s playbook that this junior can follow—opinionated, slightly conservative, but grounded in real‑world experience.&lt;/p&gt;

&lt;p&gt;That’s not as flashy as a new parameter count for a model, but for teams that ship web apps week after week, this is where AI genuinely starts to feel like infrastructure rather than a toy. The browser stops being the final black‑box stage of the pipeline and becomes a programmable surface the agent can reason about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Concrete Use Cases That Actually Make Sense
&lt;/h2&gt;

&lt;p&gt;If you ignore the hype and look at the workflows the docs emphasize, a few grounded use cases pop out. The most obvious is &lt;strong&gt;automated quality gates&lt;/strong&gt;: have an agent run Lighthouse audits on every preview deployment, flag anything that drops below a threshold, and propose Modern Web Guidance–aligned fixes before a human even opens the URL.&lt;/p&gt;

&lt;p&gt;Another is &lt;strong&gt;environment‑aware debugging&lt;/strong&gt;. The DevTools for agents documentation shows examples of simulating locations (like Berlin) and verifying that a store locator behaves correctly, or testing responsive layouts on mobile breakpoints. Instead of bouncing QA engineers between devices and VPNs, you can let an agent script those flows, collect screenshots and logs, and surface only the cases that fail.&lt;/p&gt;

&lt;p&gt;The third is &lt;strong&gt;extension and WebMCP tooling&lt;/strong&gt;, which came up both in the DevTools for agents docs and the I/O developer recap. For teams experimenting with WebMCP to expose structured tools to browser‑based agents, having DevTools‑level visibility into how those tools are invoked—and where they break—looks essential. That’s the kind of plumbing that makes “agents in the browser” feel less like a demo and more like something you’d risk in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where This Still Falls Short
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;None of this magically makes AI a senior engineer&lt;/strong&gt;. The Chrome team is explicit that DevTools for agents is about visibility and automation, not judgment. An agent can run audits and suggest fixes, but it doesn’t understand your product roadmap, business trade‑offs, or how a specific regression will land with your users.&lt;/p&gt;

&lt;p&gt;There’s also a &lt;strong&gt;trust question&lt;/strong&gt;. Giving an agent write access to your codebase is one thing; giving it write access plus direct control of your browser session, authenticated state, and extension environment is another. The documentation talks about using it as a tool in your workflow, but in practice teams will need guardrails—clear scopes, review steps, and probably some internal policies on what agents are allowed to touch.&lt;/p&gt;

&lt;p&gt;Finally, &lt;strong&gt;Modern Web Guidance is opinionated by design&lt;/strong&gt;. That’s good for consistency but can be limiting if you’re working on something that deliberately pushes browser capabilities beyond the comfort zone of a curated skill set. I expect early adopters will run into those edges and either extend the skills or selectively disable them where they conflict with legitimate experimentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I’d Actually Use This on a Real Team
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If I were integrating this into a real web stack, I wouldn’t start by letting the agent auto‑merge fixes. I’d start by letting it &lt;strong&gt;watch and report&lt;/strong&gt;. For example, wire up DevTools for agents to run on every pull request preview, with Modern Web Guidance configured for your Baseline targets, and have it produce a structured report: what audits it ran, what failed, and suggested code changes in a separate patch.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;From there, I’d gradually give it narrow powers. Maybe the agent can &lt;strong&gt;auto‑fix&lt;/strong&gt; alt‑text issues and color contrast problems, since those are relatively low‑risk and well‑defined. Maybe it can propose but not apply performance tweaks, leaving a human to decide whether a particular lazy‑loading strategy or bundling change is worth the trade‑offs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Over time, if the signal proves reliable, you could start treating this combo—DevTools for agents plus Modern Web Guidance—as a sort of &lt;strong&gt;web quality coprocessor&lt;/strong&gt;: something that runs continuously alongside your normal CI, catching the mundane but important issues that humans miss when they’re in a rush. That’s not science fiction; it’s basically just operationalizing what Google demoed in the I/O ’26 sessions and then exposed through the open Chrome and I/O docs.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why This Might Be One of I/O ’26’s Most Important Announcements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;I/O this year had plenty of “headline” moments around models and agent platforms, and those matter. But for day‑to‑day developers, the combination of Chrome DevTools for agents and Modern Web Guidance feels like the kind of change we’ll notice more in six to twelve months than in six days.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;By giving agents high‑fidelity access to the browser runtime and pairing that with a shared, opinionated definition of “good web,” Google is quietly rewriting the contract between web developers and their tools. Instead of hoping that an AI assistant understands your app from a code snippet, you can put it in front of the real thing and ask it to prove that it understands what it’s seeing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;That’s not a magic future where agents replace web teams. It’s a pragmatic step toward something more useful: agents that behave less like autocomplete and more like reliable collaborators—especially in the messy, browser‑only corners of our work that we’ve never really been able to automate well. And for me, that’s the part of I/O ’26 that feels most likely to change how we build for the web.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Thank you for reading. If you have enjoyed the article, do share it with the community &amp;amp; spread the word.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>googleiochallenge</category>
      <category>ai</category>
      <category>google</category>
    </item>
    <item>
      <title>Time to say goodbye to Webpack?</title>
      <dc:creator>Gaurav Behere</dc:creator>
      <pubDate>Thu, 13 Jan 2022 09:50:25 +0000</pubDate>
      <link>https://dev.to/gauravbehere/time-to-say-goodbye-to-webpack-2kn8</link>
      <guid>https://dev.to/gauravbehere/time-to-say-goodbye-to-webpack-2kn8</guid>
      <description>&lt;p&gt;Before we answer the big question, lets look at why we are even considering it.&lt;/p&gt;

&lt;p&gt;If you look at bestofJS data for 2021, you would see that the rising star in the build tools category is &lt;code&gt;Vite&lt;/code&gt;, leaving &lt;code&gt;Webpack&lt;/code&gt; far behind in terms of popularity.&lt;br&gt;
Check out more stats here:&lt;br&gt;
&lt;a href="https://risingstars.js.org/2021/en#section-build" rel="noopener noreferrer"&gt;2021 JavaScript Rising Stars&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftrt3d86jztveuw01blup.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftrt3d86jztveuw01blup.png" alt="Popular build tools" width="800" height="718"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Lets have a closer look at &lt;code&gt;Vite&lt;/code&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Vite (French word for "quick", pronounced /vit/, like "veet") is a build tool that aims to provide a faster and leaner &lt;code&gt;development&lt;/code&gt; experience for modern web projects.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Please note the emphasis on &lt;code&gt;development&lt;/code&gt;. &lt;code&gt;Vite&lt;/code&gt; does not promise a multifold optimization or better production experience. So don't expect your production build to be optimized or any drastic reduction in the bundle size you generate.&lt;/p&gt;
&lt;h3&gt;
  
  
  So what does &lt;code&gt;Vite&lt;/code&gt; do to make the development experience better?
&lt;/h3&gt;

&lt;p&gt;It consists of two major parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A dev server that provides rich feature enhancements over native ES modules, for example extremely fast Hot Module Replacement (HMR).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A build command that bundles your code with Rollup, pre-configured to output highly optimized static assets for production.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Vite&lt;/code&gt; is opinionated and comes with sensible defaults out of the box, but is also highly extensible via its Plugin API and JavaScript API with full typing support.&lt;/p&gt;




&lt;p&gt;It has been long since we have been writing JS code in a modular fashion specially since ES6 modules. Since not a lot of browsers were handling loading ES6 modules natively, we have the concept of bundling our code, using tools that crawl, process and concatenate our source modules into files that can run in the browser.&lt;/p&gt;

&lt;p&gt;Tools like Webpack, parcel &amp;amp; rollup do the same job.&lt;br&gt;
When you start a project, the size &amp;amp; number of JS modules may look like a smaller problem but as you write more code, the project grows &amp;amp; you see that starting a dev server takes a long time.&lt;br&gt;
Since it has to transpile the code &amp;amp; concatenate the code in a way that can be loaded in browsers.&lt;br&gt;
The slow feedback loop can greatly affect developers' productivity and happiness.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Vite aims to address these issues by leveraging new advancements in the ecosystem: the availability of native ES modules in the browser, and the rise of JavaScript tools written in compile-to-native languages.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Vite&lt;/code&gt; splits the bundles into two parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;External dependencies (Vendor code): Dependencies are mostly plain JavaScript that do not change often during development. &lt;br&gt;
&lt;strong&gt;Vite pre-bundles dependencies using esbuild.&lt;/strong&gt; Esbuild pre-bundles dependencies 10-100x faster than JavaScript-based bundlers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your code (ES modules): &lt;strong&gt;Vite serves source code over native ESM.&lt;/strong&gt; This is essentially letting the browser take over part of the job of a bundler. &lt;code&gt;Vite&lt;/code&gt; only needs to transform and serve source code on demand, as the browser requests it.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here, &lt;code&gt;Vite&lt;/code&gt; assumes that while you are developing in your local machine you would have latest of browsers that support loading ES6 modules natively.&lt;/p&gt;
&lt;h2&gt;
  
  
  That essentially means no time spent on bundling your code before the server can start.
&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.amazonaws.com%2Fuploads%2Farticles%2F656g1l249uei8twera71.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F656g1l249uei8twera71.png" alt="Bundling before server start" width="800" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7y8bsd1kkkxj7c69jg4s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7y8bsd1kkkxj7c69jg4s.png" alt="No Bundling" width="799" height="379"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Awesome, so why bundle for production?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Though most of the browsers now support loading ES modules natively, if not all of your target audience is on latest browsers, you still need bundling.&lt;/li&gt;
&lt;li&gt;If you don't bundle, you are going to make a lot of round trips on the network to fetch modules. To get the optimal loading performance in production, it is still better to bundle your code with tree-shaking, lazy-loading and common chunk splitting (for better caching).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Getting started with &lt;code&gt;Vite&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;With minimal dev dependencies, you can be off to a flying start&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"devDependencies": {
  "@vitejs/plugin-react": "^1.1.4",
  "vite": "^2.7.10"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A very basic &lt;code&gt;vite.config.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()]
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two simple commands to start a dev server &amp;amp; make a production build:&lt;br&gt;
&lt;code&gt;vite&lt;/code&gt; &amp;amp; &lt;code&gt;vite build&lt;/code&gt; respectively.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Vite&lt;/code&gt; looks for an index html entry in the root directory from where you need to load the root/index module of your code.&lt;/p&gt;

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

&lt;p&gt;&lt;code&gt;index.html&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
  &amp;lt;div id="root"&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;script type="module" src="./index.jsx"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;index.jsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import ReactDOM from 'react-dom'
import App from './src/app';

ReactDOM.render(
    &amp;lt;React.StrictMode&amp;gt;
        &amp;lt;App /&amp;gt;
    &amp;lt;/React.StrictMode&amp;gt;,
    document.querySelector('#root')
);

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

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;src/app.jsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';

const App = () =&amp;gt; {
  return &amp;lt;&amp;gt;
    &amp;lt;div&amp;gt;Hello There&amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;Time right now: {new Date().toTimeString()}&amp;lt;/div&amp;gt;
  &amp;lt;/&amp;gt;
}

export default App;

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

&lt;/div&gt;



&lt;p&gt;Without bundling the code, server starts in a fraction of a second&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc26w1mjhy4v0cf1wazbo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc26w1mjhy4v0cf1wazbo.png" alt="Server startup" width="469" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you look at how the ES modules are loaded in the browser, note that app.jsx loaded as a native ES module&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ddunvl623gn0i0dm68r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ddunvl623gn0i0dm68r.png" alt="Resources" width="800" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Hot replacement of modules (HMR)
&lt;/h2&gt;

&lt;p&gt;Developers need to get immediate feedback of changes made in the code. You can't wait for full bundling to happen again &amp;amp; reloading the page which breaks the current state &amp;amp; flow.&lt;br&gt;
This is why some bundlers support Hot Module Replacement (HMR), allowing a module to "hot replace" itself without affecting the rest of the page. Again as the project grows, HMR also takes a long time which can be a productivity killer.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Vite&lt;/code&gt; takes an edge over other bundling tools by performing HMR over native ESM. When a file is edited, &lt;code&gt;Vite&lt;/code&gt; only needs to precisely invalidate the chain between the edited module and its closest HMR boundary (most of the time only the module itself), making HMR updates consistently fast regardless of the size of your application.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Vite&lt;/code&gt; also takes advantage of HTTP headers to speed up full page reloads. Source code module requests are made conditional via 304 Not Modified, and dependency module requests are strongly cached via Cache-Control: max-age=31536000,immutable so they don't hit the server again once cached.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Vite&lt;/code&gt; starts your dev server fast by skipping the bundling.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Vite&lt;/code&gt; make use of HTTP status codes for a faster reload &amp;amp; caching.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Vite&lt;/code&gt; uses native ESM for hot module replacement. Thus your changes reflect in your app faster.&lt;/li&gt;
&lt;li&gt;Since &lt;code&gt;Vite&lt;/code&gt; is a bit opinionated about the config, with a minimal config you are good to go.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgmzuywc6e4y1ab307lp2.gif" alt="Wow" width="498" height="245"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Server side rendering
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Vite&lt;/code&gt; is also pre-configured to handle your build as a universal app. &lt;code&gt;Vite&lt;/code&gt; can pre-render the HTML pages, so robot crawlers can fetch your page content without executing js.&lt;br&gt;
Read more &lt;a href="https://vitejs.dev/guide/ssr.html" rel="noopener noreferrer"&gt;https://vitejs.dev/guide/ssr.html&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  So should we just move to &lt;code&gt;Vite&lt;/code&gt; &amp;amp; stop using tools like Webpack?
&lt;/h2&gt;

&lt;p&gt;Coming back to the question that we started with. With all the benefits listed above, it seems promising to move to &lt;code&gt;Vite&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What gives you a lot of simpler APIs with a lot of abstraction and an opinion is often hard to configure.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Based on this principle if you use some very specific long tail configurations of Webpack, it won't be a good idea to jump to Vite rightaway. If you use Webpack with basic configurations, you should move to &lt;code&gt;Vite&lt;/code&gt; for a better developer experience.&lt;/p&gt;

&lt;p&gt;If I am starting a new project, it will be using &lt;code&gt;Vite&lt;/code&gt; for sure.&lt;/p&gt;

&lt;p&gt;Thank you for reading. If you have moved a large scale project from Webpack to &lt;code&gt;Vite&lt;/code&gt;, do share your experience. It will be great to learn from your experience.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
      <category>webpack</category>
    </item>
    <item>
      <title>Unit testing service workers</title>
      <dc:creator>Gaurav Behere</dc:creator>
      <pubDate>Wed, 15 Dec 2021 13:03:27 +0000</pubDate>
      <link>https://dev.to/gauravbehere/unit-testing-service-workers-l9j</link>
      <guid>https://dev.to/gauravbehere/unit-testing-service-workers-l9j</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Writing unit tests for service workers made easy.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fseeklogo.com%2Fimages%2FJ%2Fjest-logo-F9901EBBF7-seeklogo.com.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%2Fseeklogo.com%2Fimages%2FJ%2Fjest-logo-F9901EBBF7-seeklogo.com.png" width="600" height="600"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F694%2F1%2AaO4HRVpU1zQ22rvhAeSK1w.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%2Fmiro.medium.com%2Fmax%2F694%2F1%2AaO4HRVpU1zQ22rvhAeSK1w.png" width="694" height="339"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prelude
&lt;/h2&gt;

&lt;p&gt;While service workers amaze us with its capabilities to cache requests, edit headers before putting requests on the network etc.&lt;br&gt;
I think you will agree that unit testing service workers is not straight-forward.&lt;br&gt;
The biggest question is 'what to mock?'&lt;/p&gt;

&lt;p&gt;A big shout out to Zack Argyle for writing &lt;a href="https://github.com/zackargyle/service-workers/tree/master/packages/service-worker-mock" rel="noopener noreferrer"&gt;Service Worker Mock&lt;/a&gt;. This library prepares all the mocks &amp;amp; lets your tests have an environment where you have the recipe to test your service worker.&lt;/p&gt;

&lt;h2&gt;
  
  
  Note
&lt;/h2&gt;

&lt;p&gt;This code sample is an enhancement on top of &lt;a href="https://github.com/zackargyle/service-workers/tree/master/packages/service-worker-mock" rel="noopener noreferrer"&gt;Service Worker Mock&lt;/a&gt;. Service Worker Mock explains how to write unit tests for service works. &lt;code&gt;Since it is not maintained any more, I am writing this code sample to unblock ourselves from the current issues in that library.&lt;/code&gt;&lt;br&gt;
Tests are written using the sample service worker given at &lt;a href="https://github.com/GoogleChrome/samples/blob/gh-pages/service-worker/basic/service-worker.js" rel="noopener noreferrer"&gt;service worker example&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem with the current version (2.0.5) of service worker mock
&lt;/h2&gt;

&lt;p&gt;Object.assign(global, makeServiceWorkerEnv()) no longer puts EventTarget methods like addEventListener into the global scope because they are no longer "own" properties of ServiceWorkerGlobalScope&lt;/p&gt;

&lt;h2&gt;
  
  
  Workaround
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Make &lt;code&gt;addEventListener&lt;/code&gt; an enumerable property
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;beforeEach(() =&amp;gt; {
   const serviceWorkerEnv = makeServiceWorkerEnv();
   Object.defineProperty(serviceWorkerEnv, 'addEventListener', {
      value: serviceWorkerEnv.addEventListener,
      enumerable: true
   });
   Object.assign(global, serviceWorkerEnv)
   jest.resetModules();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Testing Event registration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;it('should add listeners', async () =&amp;gt; {
  require('../src/sample-sw');
  await self.trigger('install');
  expect(self.listeners.get('install')).toBeDefined();
  expect(self.listeners.get('activate')).toBeDefined();
  expect(self.listeners.get('fetch')).toBeDefined();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Testing cache deletion on activation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;it('should delete old caches on activate', async () =&amp;gt; {
  require('../src/sample-sw');

  // Create old cache
  await self.caches.open('OLD_CACHE');
  expect(self.snapshot().caches.OLD_CACHE).toBeDefined();

  // Activate and verify old cache is removed
  await self.trigger('activate');
  expect(self.snapshot().caches.OLD_CACHE).toStrictEqual({});
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Testing fetch event to see if it returns cached response
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;it('should return a cached response', async () =&amp;gt; {
  require('../src/sample-sw');

  const cachedResponse = { clone: () =&amp;gt; { }, data: { key: 'value' } };
  const cachedRequest = new Request('/test');
  const cache = await self.caches.open('TEST');
  cache.put(cachedRequest, cachedResponse);

  const response = await self.trigger('fetch', cachedRequest);
  expect(response.data.key).toEqual('value');
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Testing if fetch event makes network call &amp;amp; updates cache. Also test any custom logic like appending a bearer token in the request
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;it('should fetch and cache an uncached request and append the right auth token in the header', async () =&amp;gt; {
  const mockResponse = { clone: () =&amp;gt; { return { data: { key: 'value' } } } };
  global.fetch = (response) =&amp;gt; Promise.resolve({ ...mockResponse, headers: response.headers });

  require('../src/sample-sw');

  const request = new Request('/test');
  const response = await self.trigger('fetch', request);
  expect(response.clone()).toEqual(mockResponse.clone());

  expect(response.headers.get('authorization')).toBe('Bearer my secret auth');

  const runtimeCache = self.snapshot().caches.runtime;
  expect(runtimeCache[request.url]).toEqual(mockResponse.clone());
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Testing if the requests to the external domains are ignored
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;it('should ignore the requests to external world', async () =&amp;gt; {
  const mockResponse = { clone: () =&amp;gt; { return { data: { key: 'value' } } } };
  global.fetch = (response) =&amp;gt; Promise.resolve({ ...mockResponse, headers: response.headers });

  require('../src/sample-sw');

  const request = new Request('http://google.com');
  const response = await self.trigger('fetch', request);
  expect(response).not.toBeDefined();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Coverage
&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%2Fraw.githubusercontent.com%2Fgauravbehere%2Funit-test-service-worker%2Fmain%2Fcoverage.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%2Fraw.githubusercontent.com%2Fgauravbehere%2Funit-test-service-worker%2Fmain%2Fcoverage.PNG" width="800" height="322"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Epilogue
&lt;/h2&gt;

&lt;p&gt;Check out the code repo for this sample here:&lt;br&gt;
&lt;a href="https://github.com/gauravbehere/unit-test-service-worker" rel="noopener noreferrer"&gt;unit-test-service-worker&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Inversion of Control — A simple &amp; effective design principle</title>
      <dc:creator>Gaurav Behere</dc:creator>
      <pubDate>Sun, 17 Oct 2021 13:57:49 +0000</pubDate>
      <link>https://dev.to/gauravbehere/inversion-of-control-a-simple-effective-design-principle-5f7g</link>
      <guid>https://dev.to/gauravbehere/inversion-of-control-a-simple-effective-design-principle-5f7g</guid>
      <description>&lt;h3&gt;
  
  
  Reducing code complexity with IoC
&lt;/h3&gt;

&lt;h2&gt;
  
  
  Inversion of control (IoC)
&lt;/h2&gt;

&lt;p&gt;If you have heard of dependency injection(DI) you have been using inversion of control but maybe not knowingly.&lt;br&gt;
IoC is often seems used interchangeably with DI but IoC as a concept is much more than that.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;IoC is a design principle that helps you in reducing the complexity of code that you may want to ship as a reusable component or a library.&lt;br&gt;
&lt;strong&gt;DI&lt;/strong&gt; is one of the patterns that help in implementing IoC.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Usually, we have seen libraries/components implementing all the features for us &amp;amp; expose APIs to be called in a certain way to get the functionality we need. We may call the same API with a different set of parameters &amp;amp; value combinations to get what we want.&lt;/p&gt;

&lt;p&gt;There is a level of abstraction to us in a way that we need not bother about the library/component reusable code but we need to know the meaning of each option/parameter to be passed so that we can understand the API’s behavior better.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Now put yourself in the shoes of the guy who wrote that library or the reusable component.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There is n number of use cases that he needs to support out of the same piece of code. There can be different values of the parameters &amp;amp; different combinations of those which may result in the same API or component to behave differently.&lt;/p&gt;
&lt;h3&gt;
  
  
  What does this translate to in code?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Lots of IF ELSE statements&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  What does it lead to?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;More cyclomatic complexity&lt;/li&gt;
&lt;li&gt;Less maintainable code&lt;/li&gt;
&lt;li&gt;Lengthier documentation about all the options &amp;amp; their combinations&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgflip.com%2F42lrta.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgflip.com%2F42lrta.jpg" width="500" height="756"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Any new feature that our generic component now has to support will have to be done very carefully so that we don’t break any existing support.&lt;/p&gt;

&lt;p&gt;When we refactor the code it is not easy to get away with any option or any conditional branch as we may not know who is consuming our component using that code flow.&lt;/p&gt;

&lt;p&gt;All these are very usual problems we see almost every day, isn’t it? This is an ever-growing problem too as the request for new functionalities with more if-else will keep coming.&lt;br&gt;
Let’s look at this piece of code to understand the problem better.&lt;/p&gt;

&lt;p&gt;You are writing a function that does the sorting of an array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const sortArray = (array) =&amp;gt; array.sort();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At a very basic level, it just returns the native sort. This is not sufficient as it doesn’t work well with numbers &amp;amp; custom sort for objects, also the default order of sort would be ascending. Let's add these features one by one.&lt;/p&gt;

&lt;p&gt;Let us add support for descending sort:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// order = 1 -&amp;gt; ascending
// order = 2 -&amp;gt; descending
const sortArray = (array, order=1) =&amp;gt; {
  if(order === 1)
    return array.sort();
  else if(order === 2)
    return array.sort((a,b) =&amp;gt; b - a);
  else
   console.error("Unsupported sort order provided")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let us add support for sorting objects with a specified key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// @param order(number) = 1 -&amp;gt; ascending
// @param order(number) = 2 -&amp;gt; descending
// @param objectSort(boolean) 
const sortArray = (array, objectSort, key, order=1) =&amp;gt; {
  if(objectSort) {
    if(order === 1)
      return array.sort((a,b) =&amp;gt; a[key] - b[key]);
    else if(order === 2)
      return array.sort((a,b) =&amp;gt; b[key] - a[key]);
    else
     console.error("Unsupported sort order provided")
  }
  else {
    if(order === 1)
      return array.sort();
    else if(order === 2)
      return array.sort((a,b) =&amp;gt; b - a);
    else
     console.error("Unsupported sort order provided")
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see that addition of features is adding code paths &amp;amp; branches in our code. Now say we need to support a case insensitive sort based on an option &amp;amp; we want to keep all the undefined values at the start of the array, that too based on an option, how many more if-else do we need?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This list of features is ever-growing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I took the example of sorting as a library function because the native sorting in JavaScript is also based on the principle of IoC.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inversion of Control
&lt;/h2&gt;

&lt;p&gt;As Wikipedia explains it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A software architecture with this design inverts control as compared to traditional procedural programming: in traditional programming, the custom code that expresses the purpose of the program calls into reusable libraries to take care of generic tasks, but with inversion of control, it is the framework that calls into the custom, or task-specific, code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In simple terms, in the inversion of control, the library or the reusable component lets the consumer take control of what the functionality is &amp;amp; it provides an abstraction on top of it.&lt;/p&gt;

&lt;p&gt;Now imagine passing the sorting method as a parameter to the library &amp;amp; it actually invokes your own sorting method to do the sorting.&lt;/p&gt;

&lt;h3&gt;
  
  
  How does it help?
&lt;/h3&gt;

&lt;p&gt;The extensibility of functionality is now independent of the code complexity in the library rather the consumer gets a handle to override the default behavior in its own way.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const sortArray = (array, sortFunction) =&amp;gt; {
  if (sortFunction) {
    return array.sort(sortFunction);
  }
  return array.sort();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Testability&lt;/strong&gt;: We can substitute the core functionalities with mocks during the testing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Substitutability&lt;/strong&gt;: We enable a &lt;em&gt;plugin architecture&lt;/em&gt; that makes it easy for us to swap out plugins, and program against code that doesn’t yet exist. All we need to do to substitute the current dependency is to create a new one that adheres to the contract defined by the interface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility&lt;/strong&gt;: According to the &lt;em&gt;“Open Closed Principle”&lt;/em&gt;, a system should be open for extension but closed for modification. That means if we want to extend the system, we need only create a new plugin in order to extend the current behavior.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delegation&lt;/strong&gt;: IoC is the phenomenon we observe when we delegate behavior to be implemented by someone else but provide the hooks/plugins/callbacks to do so. We design the current component to invert control to another one. Lots of web frameworks are built on this principle.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are many real-life use cases where you would have seen IoC in action. A good example is a state reducer pattern.&lt;br&gt;
React, rather than providing a complex way of managing your state, lets you do that with your own reducer function &amp;amp; lets you provide your reducer as a hook before rendering your components.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dependency Injection&lt;/strong&gt; in angular is also based on this principle. Dependency Injection (DI) is one of the implementations of IoC based on the composition of dependencies in the container (the library).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hooks in React are based on the IoC too.&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;Though IoC is a good principle to follow &amp;amp; there is a large number of libraries following it, it should be a conscious decision to choose IoC. In case you are aware of all the possible functionalities &amp;amp; code branches, a non-inverted control would make the consumption of the library easier. If you dealing with unknown extensibilities, it would be recommended to implement an inverted control.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>architecture</category>
      <category>design</category>
    </item>
    <item>
      <title>Re-architecting authentication with Service Workers</title>
      <dc:creator>Gaurav Behere</dc:creator>
      <pubDate>Mon, 13 Sep 2021 06:06:42 +0000</pubDate>
      <link>https://dev.to/gauravbehere/re-architecting-authentication-with-service-workers-4j6j</link>
      <guid>https://dev.to/gauravbehere/re-architecting-authentication-with-service-workers-4j6j</guid>
      <description>&lt;p&gt;A use case of changing the authentication mechanism of a web application without touching a lot of legacy codebase&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
Many times you would encounter situations where you have a legacy codebase in front of you which has been in the market for quite a while. It may be written in a technology that is seeing a downward trend in terms of popularity. You cannot make a change very easily in the architecture of such applications as the amount of risk, testing efforts &amp;amp; impact is huge.&lt;br&gt;
Let me run you through such a use case where we recently had to change the authentication mechanism of an existing legacy web application from a JSP session &amp;amp; a cookie-based authentication mechanism to an MSAL (Microsoft Authentication Library) token-based authentication method.&lt;br&gt;
What this essentially means is the login should grant a token to the web application acquiring the token using MSAL (react-msal) in our case &amp;amp; the same token should be used for making further calls to the server.&lt;br&gt;
Read more about MSAL tokens here:&lt;br&gt;
&lt;a href="https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/acquire-token.md" rel="noopener noreferrer"&gt;https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/acquire-token.md&lt;/a&gt;&lt;br&gt;

&lt;h2&gt;
  
  
  Challenges
&lt;/h2&gt;

&lt;p&gt;There are two challenges we are looking at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;b&gt;Changes to the webserver&lt;/b&gt;: The web server should be able to authenticate our requests with the token that the client application is going to send as a bearer token.&lt;/li&gt;
&lt;li&gt;
&lt;b&gt;Changes to the legacy UI code written in JSP&lt;/b&gt;: The amount of legacy code which is an amalgamation of many UI technologies where there are requests like POST from FORM submits, XHR calls, calls through native JS fetch, Jquery’s $.ajax &amp;amp; a bit of axios too. It becomes very hard to avoid changes in almost every part of the code &amp;amp; still get the new authentication mechanism working where every call to our server should have a bearer token attached to the HTTP header.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1050%2F1%2AkFSS6PQtTtxIG66AVRJOwQ.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%2Fmiro.medium.com%2Fmax%2F1050%2F1%2AkFSS6PQtTtxIG66AVRJOwQ.png" width="800" height="323"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Adding to the complexity of the application, the code base grew up with a lot of acquisitions of companies adding to the integrations in the existing codebase. Thus the application grew horizontally in terms of technology over the last 10 years.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1050%2F0%2A6knY-qVrAJOBwvx1.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%2Fmiro.medium.com%2Fmax%2F1050%2F0%2A6knY-qVrAJOBwvx1.png" width="800" height="256"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also when you have such a legacy codebase, it becomes hard to keep the knowledge fresh. There are pieces of the code that developers might not have even looked at for a long long time. Touching such code may result in unaccounted for side effects as the application has a significant number of customers who are using different versions &amp;amp; flows of the application.&lt;/p&gt;



&lt;h3&gt;
  
  
  How can we have a centralized solution which avoids making changes to a lot of files?
&lt;/h3&gt;

&lt;p&gt;&lt;b&gt;Service workers &amp;amp; promises to the rescue.&lt;/b&gt;&lt;br&gt;
We try to avoid changes in the front-end code updating the APIs to authenticate based on the incoming MSAL token.&lt;br&gt;
The solution is to capture all the network calls originated from the web application &amp;amp; append a bearer token in the HTTP header in the request.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1400%2F1%2AQpmgo07lva2ft-0iMFMusA.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%2Fmiro.medium.com%2Fmax%2F1400%2F1%2AQpmgo07lva2ft-0iMFMusA.png" width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Take a hold of all the network calls generated by your web application using a service worker registered at the root of your web application.
&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="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;some dummy token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// This needs to be requested from MSAL library&lt;/span&gt;

  &lt;span class="c1"&gt;// Responding with a custom promise&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;promise&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;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// edit event.request &amp;amp; respond with a fetch of a new request with new headers&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;sourceHeaders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;pair&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;sourceHeaders&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;pair&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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pair&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newHeaders&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;sourceHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authorization&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;Bearer: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;token&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;newRequest&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;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newHeaders&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respondWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;promise&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;In the fetch event we need to respond with a new request that has HTTP headers we need. In the gist above, we are just adding a dummy auth token to the request. Here we do a couple of things:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a. We copy all the headers of the incoming request.
b. We create a new request with incoming headers &amp;amp; a new authorization header containing a token.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;b&gt;Now let us get the right token.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Here comes the tricky part. A service worker comes with its own limitations, it has no access to DOM &amp;amp; it can’t access shared storage between the page &amp;amp; itself. Somehow we need to get the token from the main thread &amp;amp; the container app.&lt;br&gt;
Here is a good article explaining how to establish communication between a service worker &amp;amp; the container page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felixgerschau.com/how-to-communicate-with-service-workers/" rel="noopener noreferrer"&gt;https://felixgerschau.com/how-to-communicate-with-service-workers/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We choose the Broadcast API to get away with the need of the two parties to remember the ports to have a 1:1 communication channel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1050%2F1%2ANFN2uS3PocIlm9Y0R6Xvrg.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%2Fmiro.medium.com%2Fmax%2F1050%2F1%2ANFN2uS3PocIlm9Y0R6Xvrg.png" width="799" height="213"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Create a channel for communication&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;channel&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;BroadcastChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TOKEN_EXCHANGE&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;getAToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;promise&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;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Listen to token response&lt;/span&gt;
    &lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="c1"&gt;// Send a token request to the main thread&lt;/span&gt;
    &lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;TOKEN_REQUEST&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;promise&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Changes in the container app
&lt;/h3&gt;

&lt;p&gt;The container app now needs to listen to the messages on the same broadcast channel &amp;amp; respond with a token.&lt;br&gt;
This allows up to keep the front end legacy code as-is &amp;amp; at the same time have a new authentication mechanism.&lt;/p&gt;

&lt;h4&gt;
  
  
  Things to note
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;As our solution is based on service workers, promises &amp;amp; Broadcast API, browser compatibility can be a limitation.&lt;/li&gt;
&lt;li&gt;We still had to re-factor the APIs to honor tokens in the request for authentication.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>architecture</category>
      <category>authentication</category>
    </item>
    <item>
      <title>Must-Have Weapons in Your React Armory</title>
      <dc:creator>Gaurav Behere</dc:creator>
      <pubDate>Mon, 13 Sep 2021 05:48:48 +0000</pubDate>
      <link>https://dev.to/gauravbehere/must-have-weapons-in-your-react-armory-1pcc</link>
      <guid>https://dev.to/gauravbehere/must-have-weapons-in-your-react-armory-1pcc</guid>
      <description>&lt;p&gt;Weapons (tools) make a soldier (developer) effective. Advanced and effective weapons (tools) in your armory ensure you have the firepower to handle the complexity of an ever-growing code base.&lt;br&gt;
Let’s look at a few of the tools I used in my last project. These tools helped me to write code quickly yet maintain quality.&lt;/p&gt;



&lt;h2&gt;
  
  
  React Dev Tools
&lt;/h2&gt;

&lt;p&gt;Programming is 20% coding and 80% debugging. Debugging is what makes a programmer efficient in comparison to others.&lt;br&gt;
React Developer Tools let you inspect a React tree, including the component hierarchy, props, state, and more. To get started, just open the React Developer Tools and switch to the React Components or React Profiler tab.&lt;br&gt;
By selecting one of the components in the tree, you can inspect and edit its current props and state in the panel on the right. In the breadcrumbs, you can inspect the selected component, the component that created it, the component that created that one, and more.&lt;br&gt;
React developer tools are available for &lt;a href="https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi" rel="noopener noreferrer"&gt;Chrome&lt;/a&gt; and &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/react-devtools" rel="noopener noreferrer"&gt;Firefox&lt;/a&gt; as an extension.&lt;/p&gt;



&lt;h2&gt;
  
  
  Styled Components
&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%2Fmiro.medium.com%2Fmax%2F516%2F1%2ACrJ9gMVMHtMOhGgY1obVJg.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%2Fmiro.medium.com%2Fmax%2F516%2F1%2ACrJ9gMVMHtMOhGgY1obVJg.png" width="258" height="258"&gt;&lt;/a&gt; &lt;br&gt;
While styling components, we also have to take care of vendor prefixes for cross-browser operability. If we’re using LESS or SASS we have to compile code to CSS.&lt;br&gt;
With a component being an individual entity and a basic building block for building apps, it’s recommended for styling to be included within the component, rather than the container app taking care of styling with class names.&lt;br&gt;
Styled components allow us to keep the styles within the component, coupled with the JavaScript code.&lt;br&gt;
Read about some more benefits &lt;a href="https://www.styled-components.com/docs/basics#motivation" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;



&lt;h2&gt;
  
  
  React-Intl
&lt;/h2&gt;

&lt;p&gt;Having strings, a lot of text in the UI, and having to internationalize it can be painful at times. With the right translation based on browser locale or user preference, presenting the user interface in a different language can be tricky.&lt;br&gt;
React-Intl handles it in an elegant way, wrapping your components in a scope and rendering strings based on the locale.&lt;br&gt;
With support for formatting dates, numbers, plurals, etc out of the box, it makes handling such translations easy. Moreover, for a fully-fledged translation conversion, you can have translations based on languages you want to support and you can configure React-Intl to pick up the right translation file at runtime.&lt;br&gt;
Read more &lt;a href="https://github.com/formatjs/react-intl/blob/master/docs/Getting-Started.md#introduction" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;



&lt;h2&gt;
  
  
  Storybook
&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%2Fpbs.twimg.com%2Fprofile_images%2F1100804485616566273%2FsOct-Txm.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%2Fpbs.twimg.com%2Fprofile_images%2F1100804485616566273%2FsOct-Txm.png" width="400" height="400"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://storybook.js.org/" rel="noopener noreferrer"&gt;Storybook&lt;/a&gt; allows you to write and test components in isolation.&lt;br&gt;
When there are multiple people working on UI components that need integration at a later point in time, storybook makes it easier for individual developers to write and test their components in isolation.&lt;br&gt;
Moreover, the storybook also serves as a living document of what has been done so far. You can look at all the components at a glance and check how they behave. You can play with a component by modifying supplied props and testing its behavior.&lt;br&gt;
I may sound crazy if you’ve only worked with a smaller codebase but when projects grow, there are times when a developer ends up writing a component that already existed or a behavior variation of an existing component could have met the purpose. In such cases, the storybook acts as a go-to page to see what components &amp;amp; what behaviors already exist.&lt;br&gt;
Check out how you can add stories to your components and make it available as a storybook, &lt;a href="https://github.com/storybookjs/storybook" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;



&lt;h2&gt;
  
  
  React Testing Library
&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%2Fraw.githubusercontent.com%2Ftesting-library%2Freact-testing-library%2Fmain%2Fother%2Fgoat.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%2Fraw.githubusercontent.com%2Ftesting-library%2Freact-testing-library%2Fmain%2Fother%2Fgoat.png" width="128" height="128"&gt;&lt;/a&gt;&lt;br&gt;
It comes last in this piece but this is the most important one and a lifesaver when testing React apps.&lt;br&gt;
Based on this principle, and I quote the author,&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;The more your tests resemble the way your software is used, the more confidence they can give you.&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;The biggest confusion I have as a developer is when writing tests whether my suite is under mocked or over mocked. Am I testing with the right expectations?&lt;br&gt;
React Testing Library comes up with guidelines about what should be tested, allowing us to test the DOM changes and updates as good as what the end-user will perceive.&lt;br&gt;
Combine it with Jest and you get a robust set of APIs that you need to be able to render your components in isolation, mimic behavioral changes, and observe DOM changes.&lt;br&gt;
Get started &lt;a href="https://testing-library.com/docs/dom-testing-library/intro" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;br&gt;&lt;br&gt;
I have listed the tools that have helped me. That said, there may be tools that have helped you, which you think are better than the ones I’ve listed. I’d love to hear about them.

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>tooling</category>
    </item>
    <item>
      <title>JavaScript - All The Things, Mostly</title>
      <dc:creator>Gaurav Behere</dc:creator>
      <pubDate>Wed, 01 Sep 2021 04:56:02 +0000</pubDate>
      <link>https://dev.to/gauravbehere/js-know-it-all-5f3b</link>
      <guid>https://dev.to/gauravbehere/js-know-it-all-5f3b</guid>
      <description>&lt;h2&gt;
  
  
  JavaScript - All The Things, Mostly
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Curated list of awesome JS resources
&lt;/h3&gt;



&lt;h2&gt;
  
  
  Books
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.oreilly.com/library/view/javascript-the-good/9780596517748/" rel="noopener noreferrer"&gt;JavaScript: The Good Parts - Douglas Crockford&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.oreilly.com/library/view/programming-javascript-applications/9781491950289/" rel="noopener noreferrer"&gt;Programming JavaScript Applications - Eric Elliott&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.oreilly.com/library/view/javascript-the-definitive/9781491952016/" rel="noopener noreferrer"&gt;JavaScript: The Definitive Guide, 7th Edition - David Flanagan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://addyosmani.com/resources/essentialjsdesignpatterns/book/" rel="noopener noreferrer"&gt;Learning JavaScript Design Patterns - Addy Osmani&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.oreilly.com/library/view/you-dont-know/9781491905241/" rel="noopener noreferrer"&gt;You Don't Know JS: ES6 &amp;amp; Beyond - Kyle Simpson&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://exploringjs.com/es6/" rel="noopener noreferrer"&gt;Exploring ES6 - Axel Rauschmayer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.oreilly.com/library/view/high-performance-javascript/9781449382308/" rel="noopener noreferrer"&gt;High Performance JavaScript - Nicholas C. Zakas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.oreilly.com/library/view/javascript-for-kids/9781457189838/" rel="noopener noreferrer"&gt;JavaScript for Kids - Nick Morgan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.oreilly.com/library/view/eloquent-javascript/9781593272821/" rel="noopener noreferrer"&gt;Eloquent JavaScript - Marijn Haverbeke&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="http://effectivejs.com/" rel="noopener noreferrer"&gt;Effective JavaScript - David Herman&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;




&lt;h2&gt;
  
  
  Video Tutorials
&lt;/h2&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=8aGhZQkoFbQ" rel="noopener noreferrer"&gt;What the heck is the event loop anyway? | Philip Roberts | JSConf EU&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=W6NZfCO5SIk" rel="noopener noreferrer"&gt;JavaScript Tutorial for Beginners: Learn JavaScript in 1 Hour [2020]&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=Qqx_wzMmFeA" rel="noopener noreferrer"&gt;JavaScript Tutorial for Beginners - Full Course in 8 Hours [2020]&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=e-5obm1G_FY" rel="noopener noreferrer"&gt;Learning Functional Programming with JavaScript - Anjana Vakil - JSUnconf&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=hQVTIJBZook" rel="noopener noreferrer"&gt;JavaScript: The Good Parts&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=t3R3R7UyN2Y" rel="noopener noreferrer"&gt;ES6 and Beyond Workshop Part 1 at PayPal (Jan 2017)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=eOKQDh50ECU" rel="noopener noreferrer"&gt;ES6 and Beyond Workshop Part 2 at PayPal (March 2017)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=lil4YCCXRYc" rel="noopener noreferrer"&gt;Jafar Husain: Async Programming in ES7 | JSConf US 2015&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=Bv_5Zv5c-Ts" rel="noopener noreferrer"&gt;JavaScript: Understanding the Weird Parts - The First 3.5 Hours&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=HF1luRD4Qmk" rel="noopener noreferrer"&gt;Debugging The Web (Chrome Dev Summit 2016)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=dxzBZpzzzo8" rel="noopener noreferrer"&gt;Rediscovering JavaScript by Venkat Subramaniam&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=p-iiEDtpy6I" rel="noopener noreferrer"&gt;Franziska Hinkelmann: JavaScript engines - how do they even? | JSConf EU&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=FmiQr4nfoPQ" rel="noopener noreferrer"&gt;Recursion, Iteration, and JavaScript: A Love Story - Anjana Vakil | JSHeroes 2018&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=PkZNo7MFNFg" rel="noopener noreferrer"&gt;Learn JavaScript - Full Course for Beginners&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=PFmuCDHHpwk" rel="noopener noreferrer"&gt;Object-oriented Programming in JavaScript: Made Super Simple | Mosh&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;




&lt;h2&gt;
  
  
  Courses
&lt;/h2&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://kentcdodds.com/workshops/javascript-fundamentals" rel="noopener noreferrer"&gt;JavaScript Fundamentals Workshop&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://www.codecademy.com/learn/introduction-to-javascript" rel="noopener noreferrer"&gt;Learn JavaScript&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://www.udemy.com/course/the-complete-javascript-course/" rel="noopener noreferrer"&gt;The Complete JavaScript Course 2020&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/playlist?list=PL4cUxeGkcC9i9Ae2D9Ee1RvylH38dKuET" rel="noopener noreferrer"&gt;JavaScript Tutorials for Beginners&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/playlist?list=PLDyQo7g0_nsX8_gZAB8KD1lL4j4halQBJ" rel="noopener noreferrer"&gt;Getting Started With Javascript | Javascript Tutorial For Beginners&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://www.pluralsight.com/courses/javascript-best-practices" rel="noopener noreferrer"&gt;JavaScript Best Practices&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;a href="https://hackr.io/tutorials/learn-javascript" rel="noopener noreferrer"&gt;JavaScript Tutorials and Courses&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;




&lt;h2&gt;
  
  
  Useful Blogs/Articles
&lt;/h2&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/previous-versions/msdn10/ff852808(v=msdn.10)" rel="noopener noreferrer"&gt;Prototypes and Inheritance in JavaScript&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://www.sitepoint.com/proper-error-handling-javascript/" rel="noopener noreferrer"&gt;A Guide to Proper Error Handling in JavaScript&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://developers.google.com/web/fundamentals/primers/service-workers" rel="noopener noreferrer"&gt;Service Workers: an Introduction&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;a href="https://dev.to/arnavaggarwal/10-javascript-concepts-you-need-to-know-for-interviews"&gt;10 JavaScript concepts you need to know for interviews&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;




&lt;h2&gt;
  
  
  Websites
&lt;/h2&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://developers.google.com/web" rel="noopener noreferrer"&gt;Google Web Developers&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="http://es6-features.org/" rel="noopener noreferrer"&gt;ECMAScript 6&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://nodejs.org/en/docs/es6/" rel="noopener noreferrer"&gt;Node JS&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics" rel="noopener noreferrer"&gt;MDN&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://javascript.info/" rel="noopener noreferrer"&gt;JavaScript.info&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;a href="http://superherojs.com/" rel="noopener noreferrer"&gt;Superhero.js&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;




&lt;h2&gt;
  
  
  Dev Channels
&lt;/h2&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/c/JSConfEU/videos" rel="noopener noreferrer"&gt;JSConf&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/c/GoogleChromeDevelopers/videos" rel="noopener noreferrer"&gt;Google Chrome Developers&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://web.dev/learn/" rel="noopener noreferrer"&gt;web.dev&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;a href="https://twitter.com/JavaScriptDaily" rel="noopener noreferrer"&gt;JavaScript Daily&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;




&lt;h2&gt;
  
  
  Publications/Magazines
&lt;/h2&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://medium.com/tag/javascript" rel="noopener noreferrer"&gt;JavaScript on Medium&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://www.smashingmagazine.com/category/javascript" rel="noopener noreferrer"&gt;JavaScript on Smashing Magazine&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/t/javascript"&gt;JavaScript on Dev.to&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://javascriptweekly.com/" rel="noopener noreferrer"&gt;JavaScript Weekly&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;a href="https://nodeweekly.com/" rel="noopener noreferrer"&gt;Node Weekly&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;




&lt;h2&gt;
  
  
  Useful Github Links
&lt;/h2&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/leonardomso/33-js-concepts" rel="noopener noreferrer"&gt;33-js-concepts&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/lydiahallie/javascript-questions" rel="noopener noreferrer"&gt;JavaScript Questions&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/h5bp/Front-end-Developer-Interview-Questions/blob/master/src/questions/javascript-questions.md" rel="noopener noreferrer"&gt;Front-end-Developer-Interview-Questions&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/DrkSephy/es6-cheatsheet" rel="noopener noreferrer"&gt;es6-cheatsheet&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;a href="https://github.com/ryanmcdermott/clean-code-javascript" rel="noopener noreferrer"&gt;clean-code-javascript&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;




&lt;h2&gt;
  
  
  People
&lt;/h2&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://twitter.com/BrendanEich" rel="noopener noreferrer"&gt;BrendanEich&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://twitter.com/kentcdodds" rel="noopener noreferrer"&gt;Kent C. Dodds&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://twitter.com/addyosmani" rel="noopener noreferrer"&gt;Addy Osmani&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://twitter.com/paul_irish" rel="noopener noreferrer"&gt;Paul Irish&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/douglascrockford" rel="noopener noreferrer"&gt;Douglas Crockford&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://twitter.com/benawad/" rel="noopener noreferrer"&gt;Ben Awad&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://twitter.com/_ericelliott" rel="noopener noreferrer"&gt;Eric Elliott&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://twitter.com/dan_abramov" rel="noopener noreferrer"&gt;Dan Abramov&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://twitter.com/MarijnJH" rel="noopener noreferrer"&gt;Marijn Haverbeke&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/getify" rel="noopener noreferrer"&gt;Kyle Simpson&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href="https://twitter.com/wesbos" rel="noopener noreferrer"&gt;Wes Bos&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;a href="https://github.com/DanWahlin" rel="noopener noreferrer"&gt;Dan Wahlin&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;





These resources have helped me a lot in keeping up with JS.
If you have a suggestion, please comment. I would love to read &amp;amp; add to this.&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
