<?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: Pahan Perera</title>
    <description>The latest articles on DEV Community by Pahan Perera (@pahanperera).</description>
    <link>https://dev.to/pahanperera</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%2F766889%2F647793b1-ff72-47a1-bef3-1065e896c69f.png</url>
      <title>DEV Community: Pahan Perera</title>
      <link>https://dev.to/pahanperera</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pahanperera"/>
    <language>en</language>
    <item>
      <title>Visual Introduction to Frontend Testing Types</title>
      <dc:creator>Pahan Perera</dc:creator>
      <pubDate>Sat, 11 May 2024 06:03:27 +0000</pubDate>
      <link>https://dev.to/pahanperera/visual-introduction-to-frontend-testing-types-45oc</link>
      <guid>https://dev.to/pahanperera/visual-introduction-to-frontend-testing-types-45oc</guid>
      <description>&lt;p&gt;Frontend web applications are very crucial part of any software system. That is where users interact with our system. Therefore it is important that we test our frontend application code before and after deployment. &lt;/p&gt;

&lt;p&gt;Intention of this post is to provide an overview to different types of Frontend Tests by covering &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An introduction to different types of Frontend Tests &lt;/li&gt;
&lt;li&gt;Where each tests belong in software development cycle&lt;/li&gt;
&lt;li&gt;Scope of each tests&lt;/li&gt;
&lt;li&gt;Technologies and libraries that can be used in each tests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also this post is written with the context of a &lt;strong&gt;ReactJS&lt;/strong&gt; application, but overall concepts explained in this post can be easily applicable for any Frontend project. &lt;/p&gt;

&lt;p&gt;So Let's Get Started...!&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to Frontend Tests
&lt;/h2&gt;

&lt;p&gt;Below visualization shows the types of testing that we are going to discuss today and where each tests belong in the development and deployment cycle. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8xzr7t3fvn7m8jz96ium.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8xzr7t3fvn7m8jz96ium.png" alt="Overview of Frontend Tests Types"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before we go further, Lets remind ourself about two types of components that we see in Component based Frontend Project.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dumb/Static Components&lt;/strong&gt; - Components that ONLY uses props to communicate with external world. Normally these components are the leaf components in our component tree.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smart/Container Components&lt;/strong&gt; - These components use Dumb/Static components to make a more opinionated user experience. They communicate with external world in different ways including &lt;code&gt;fetch&lt;/code&gt; APIs, mutating global state of the application and reacts to global state changes. Custom Hooks that we write normally goes into this category. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Following diagram summarize what we just talked. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff9nwt87dry6bezoqfh1x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff9nwt87dry6bezoqfh1x.png" alt="Component Tree with Dump and Smart Components"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let's go in details of each test types&lt;/p&gt;

&lt;h3&gt;
  
  
  Unit Tests
&lt;/h3&gt;

&lt;p&gt;Unit Tests are the most famous type of developer testing type. It tests each unit or component in our frontend application in isolation. If we think of our component tree, unit tests cover our list of Dumb/Static Components&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiu4s738lcjew1j97hv30.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiu4s738lcjew1j97hv30.png" alt="Unit Testing Scope with Dumb Components"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Technologies can be used&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Jest - &lt;a href="https://jestjs.io/" rel="noopener noreferrer"&gt;https://jestjs.io/&lt;/a&gt; (Javascript Testing Framework and Runner)&lt;/li&gt;
&lt;li&gt;React Testing Library - &lt;a href="https://testing-library.com/docs/react-testing-library/intro/" rel="noopener noreferrer"&gt;https://testing-library.com/docs/react-testing-library/intro/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Component Tests
&lt;/h3&gt;

&lt;p&gt;We can identify this type as a variant of Unit Tests that specialized in testing Smart Components. Since Smart Components communicate with external world in different ways, it is important to mock these communication channels and external boundaries, so that we can test these Components in isolation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqrcolyjq2q4si940dhb8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqrcolyjq2q4si940dhb8.png" alt="Component Testing Score with Smart Components"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Technologies can be used&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Jest - &lt;a href="https://jestjs.io/" rel="noopener noreferrer"&gt;https://jestjs.io/&lt;/a&gt; (Javascript Testing Framework and Runner)&lt;/li&gt;
&lt;li&gt;React Testing Library - &lt;a href="https://testing-library.com/docs/react-testing-library/intro/" rel="noopener noreferrer"&gt;https://testing-library.com/docs/react-testing-library/intro/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Mock Service Worker - &lt;a href="https://mswjs.io/" rel="noopener noreferrer"&gt;https://mswjs.io/&lt;/a&gt; (Mocking the API Responses in the browser without creating a separate mock server)&lt;/li&gt;
&lt;li&gt;Cypress Component Testing - &lt;a href="https://docs.cypress.io/guides/component-testing/overview" rel="noopener noreferrer"&gt;https://docs.cypress.io/guides/component-testing/overview&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Snapshot Tests
&lt;/h3&gt;

&lt;p&gt;Our components changes frequently. But as developers, sometimes we only updates the component logic which does not change how the component renders on the page. Snapshot Tests make sure visualization of the component does not change unexpectedly. &lt;/p&gt;

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

&lt;p&gt;Technologies can be used&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Jest - &lt;a href="https://jestjs.io/docs/snapshot-testing" rel="noopener noreferrer"&gt;https://jestjs.io/docs/snapshot-testing&lt;/a&gt; (Javascript Testing Framework and Runner)&lt;/li&gt;
&lt;li&gt;React Testing Library - &lt;a href="https://testing-library.com/docs/react-testing-library/intro/" rel="noopener noreferrer"&gt;https://testing-library.com/docs/react-testing-library/intro/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Storybook Snapshot Testing - &lt;a href="https://storybook.js.org/docs/writing-tests/snapshot-testing" rel="noopener noreferrer"&gt;https://storybook.js.org/docs/writing-tests/snapshot-testing&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Component Level Accessibility Tests
&lt;/h3&gt;

&lt;p&gt;Accessibility tests are very important to make sure the application we build is accessible for all types of users. Normally Accessibility Tests are done manually by Accessibility Testing Experts, but there are very powerful libraries that capable of catching some obvious accessibility issues in the early stage of development cycle. &lt;/p&gt;

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

&lt;p&gt;Technologies can be used&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Jest - &lt;a href="https://jestjs.io/" rel="noopener noreferrer"&gt;https://jestjs.io/&lt;/a&gt; (Javascript Testing Framework and Runner)&lt;/li&gt;
&lt;li&gt;React Testing Library - &lt;a href="https://testing-library.com/docs/react-testing-library/intro/" rel="noopener noreferrer"&gt;https://testing-library.com/docs/react-testing-library/intro/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Axe Tools - &lt;a href="https://www.deque.com/axe/devtools/web-accessibility/" rel="noopener noreferrer"&gt;https://www.deque.com/axe/devtools/web-accessibility/&lt;/a&gt; (Provides React SDK that tests for accessibility issues in component rendering)&lt;/li&gt;
&lt;li&gt;StoryBook - &lt;a href="https://storybook.js.org/docs/writing-tests/accessibility-testing" rel="noopener noreferrer"&gt;https://storybook.js.org/docs/writing-tests/accessibility-testing&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Contract Testing
&lt;/h3&gt;

&lt;p&gt;Most Frontend Application requires a Backend API Server to fetch data. Contract Testing helps us to make sure the API contract between the Frontend Application and the Backend API Server (i.e API Request and Response) is valid and no compatibility issues after deploy. &lt;/p&gt;

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

&lt;p&gt;If we follow Consumer Driven Contact Testing (See &lt;a href="https://www.youtube.com/watch?v=U05q0zJsKsU&amp;amp;list=PLwy9Bnco-IpfZ72VQ7hce8GicVZs7nm0i" rel="noopener noreferrer"&gt;this playlist&lt;/a&gt; for more info) we can achieve following&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The new version of Frontend Application that is about to get deploy is compatible with the backend API server that is already deployed. &lt;/li&gt;
&lt;li&gt;If you are about to deploy a new version of backend API server, we can make sure we are not breaking current version of the Frontend Application that is already deployed. &lt;/li&gt;
&lt;/ul&gt;

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

&lt;h3&gt;
  
  
  Post Deployment Testing
&lt;/h3&gt;

&lt;p&gt;Most of the post deployment testing types including End-to-End Tests, Accessibility Tests and Performance Tests simulate the loading of the application in a web browser and trigger user interactions as an actual user would do in the application. &lt;/p&gt;

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

&lt;h4&gt;
  
  
  End-to-End Tests
&lt;/h4&gt;

&lt;p&gt;End-to-End Tests automatically loads the web application in the browser and simulates the user activities. For example test script would find a button in the browser and click on that and waits, similar to how actual user would do. Then our web application runs its logic, call an API server and gets all the data and display accordingly. Then test script assert the rendered data as it intends to show it to the user. &lt;/p&gt;

&lt;p&gt;Normally these test scripts are align with user stories and can be written in gherkin format as well. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/pahanperera/gherkin-style-e2e-tests-for-a-web-application-using-cucumberjs-4djl"&gt;https://dev.to/pahanperera/gherkin-style-e2e-tests-for-a-web-application-using-cucumberjs-4djl&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Technologies can be used,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cypress - &lt;a href="https://docs.cypress.io/guides/overview/why-cypress" rel="noopener noreferrer"&gt;https://docs.cypress.io/guides/overview/why-cypress&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Selenium - &lt;a href="https://www.selenium.dev/documentation/overview/" rel="noopener noreferrer"&gt;https://www.selenium.dev/documentation/overview/&lt;/a&gt; (End-to-End Test Runner) &lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Accessibility Tests
&lt;/h4&gt;

&lt;p&gt;Similar to End-to-End Tests, Accessibility tests also automatically loads the web application in the instrumented/simulated web browser and check for the visual output of the final rendered web application. &lt;/p&gt;

&lt;p&gt;These tests covers&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Evaluating page structure, color contrast, form labels, and multimedia alternatives&lt;/li&gt;
&lt;li&gt;Validating Screen Readers&lt;/li&gt;
&lt;li&gt;Keyboard only navigation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Technologies can be used,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Axe Tools - &lt;a href="https://www.deque.com/axe/devtools/web-accessibility/" rel="noopener noreferrer"&gt;https://www.deque.com/axe/devtools/web-accessibility/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://www.applause.com/blog/accessibility-testing-what-you-should-know/" rel="noopener noreferrer"&gt;https://www.applause.com/blog/accessibility-testing-what-you-should-know/&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Performance Tests
&lt;/h4&gt;

&lt;p&gt;Performance Tests determines the quality of the web application and generate reports/audits for performance, accessibility, progressive web apps, SEO, and more.&lt;/p&gt;

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

&lt;p&gt;Technologies can be used,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Google Lighthouse - &lt;a href="https://developer.chrome.com/docs/lighthouse/overview" rel="noopener noreferrer"&gt;https://developer.chrome.com/docs/lighthouse/overview&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Based on the nature of our frontend application, we may need to focus more on getting certain metrics right, rather than trying get everything. &lt;/p&gt;

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

&lt;p&gt;There are lot of other Frontend tests types that are not mentioned in this post and depending on the nature of the project we have to decide what are the types of testing are best fit for our frontend application. &lt;/p&gt;

&lt;p&gt;I hope this post gave you an idea of what types of Frontend test that you can do to make sure you deliver an quality product to your customers. &lt;/p&gt;

&lt;p&gt;❤️ Appreciate your feedback and thank you very much for reading.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>testing</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How to create a shared context between asynchronous calls in nodejs</title>
      <dc:creator>Pahan Perera</dc:creator>
      <pubDate>Sat, 28 May 2022 02:02:28 +0000</pubDate>
      <link>https://dev.to/pahanperera/how-to-create-a-shared-context-between-asynchronous-calls-in-nodejs-4kim</link>
      <guid>https://dev.to/pahanperera/how-to-create-a-shared-context-between-asynchronous-calls-in-nodejs-4kim</guid>
      <description>&lt;p&gt;👋 Hello Everyone..!!!&lt;/p&gt;

&lt;p&gt;As a javascript developer, even though you don't implement your own &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous" rel="noopener noreferrer"&gt;asynchronous&lt;/a&gt; functions very often, you are very likely to need to use them in your everyday project. &lt;/p&gt;

&lt;p&gt;Typically there are two/three ways to deal with asynchronous functions. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Callbacks&lt;/li&gt;
&lt;li&gt;Promises&lt;/li&gt;
&lt;li&gt;Async/Await (i.e Promises)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can read more about these &lt;a href="https://levelup.gitconnected.com/asynchronous-javascript-3-ways-5c5434819a14" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/p&gt;

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

&lt;p&gt;When you have a chain of asynchronous calls (callbacks or promises),  how do you share a common context between all these calls? &lt;/p&gt;

&lt;p&gt;Let's think of the following example.&lt;/p&gt;

&lt;p&gt;You are writing a function called &lt;code&gt;getCustomerOrders()&lt;/code&gt; that returns customer details along with his/her active orders. Inside that function you have to call asynchronous &lt;code&gt;getCustomer()&lt;/code&gt; and asynchronous &lt;code&gt;getOrders()&lt;/code&gt; where both of these function needs a &lt;code&gt;customerId&lt;/code&gt; from in the Request. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Furl480baj2bhf98ltbem.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Furl480baj2bhf98ltbem.png" alt="shared context between asynchronous calls"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Solution is simple right? 😊 &lt;/p&gt;

&lt;p&gt;You just extract the &lt;code&gt;customerId&lt;/code&gt; from the Request and pass it to both &lt;code&gt;getCustomer()&lt;/code&gt; and &lt;code&gt;getOrders()&lt;/code&gt; as function parameters. &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;getCustomer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;customerId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Customer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;fetchCustomerFromApi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;customerId&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;Yes, &lt;strong&gt;this is probably the best way&lt;/strong&gt; that you share context between asynchronous calls. But do you know an alternative way to share context without passing as parameters? &lt;/p&gt;

&lt;h2&gt;
  
  
  AsyncLocalStorage
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;AsyncLocalStorage&lt;/code&gt; class of &lt;code&gt;async_hooks&lt;/code&gt; module is released as part of &lt;a href="https://nodejs.org/gl/blog/release/v14.0.0/" rel="noopener noreferrer"&gt;Node.js 14&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As per the &lt;a href="https://nodejs.org/api/async_context.html" rel="noopener noreferrer"&gt;NodeJS official documentation&lt;/a&gt;  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;These classes are used to associate state and propagate it throughout callbacks and promise chains. They allow storing data throughout the lifetime of a web request or any other asynchronous duration. It is similar to thread-local storage in other languages.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In simple terms, this acts as a global variable that scoped to a particular asynchronous execution context. &lt;/p&gt;

&lt;h2&gt;
  
  
  Let's see AsyncLocalStorage in action
&lt;/h2&gt;

&lt;p&gt;Let's see how we can refactor our &lt;code&gt;getCustomerOrders()&lt;/code&gt; example to use &lt;code&gt;AsyncLocalStorage&lt;/code&gt; &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, import &lt;code&gt;AsyncLocalStorage&lt;/code&gt; from &lt;code&gt;async_hooks&lt;/code&gt; module. &lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AsyncLocalStorage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;async_hooks&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;ol&gt;
&lt;li&gt;Next, you have to create instance from &lt;code&gt;AsyncLocalStorage&lt;/code&gt; representing the data that you are going to share. In this example we are going to store the &lt;code&gt;customerId&lt;/code&gt;. &lt;/li&gt;
&lt;/ol&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;userAsyncLocalStorage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AsyncLocalStorage&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;customerId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Now, you have to wrap the &lt;code&gt;getCustomerOrders()&lt;/code&gt; function using &lt;code&gt;AsyncLocalStorage.run&lt;/code&gt; function. This is where all the magic happens. As the first parameter to the &lt;code&gt;run&lt;/code&gt; function, you can pass the data that you want to share.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;userAsyncLocalStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// customerId is read from the Request&lt;/span&gt;
      &lt;span class="na"&gt;customerId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;123456789&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;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;customer&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;getCustomer&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;orders&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;getOrders&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="c1"&gt;// write data to Response &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;customer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;


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

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Finally, inside the &lt;code&gt;getCustomer()&lt;/code&gt; and &lt;code&gt;getOrders()&lt;/code&gt; you can retrieve &lt;code&gt;customerId&lt;/code&gt; as below.&lt;/li&gt;
&lt;/ol&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;getCustomer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;customerId&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userAsyncLocalStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getStore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;fetchCustomerFromApi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;customerId&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;That is the end of very basic application using &lt;code&gt;AsyncLocalStorage&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://wiki.c2.com/?GlobalVariablesAreBad" rel="noopener noreferrer"&gt;Global state or variables are generally considered bad&lt;/a&gt;&lt;br&gt;
 as they make testing and debugging a lot harder. Therefor the pattern of using &lt;code&gt;AsyncLocalStorage&lt;/code&gt; to share business data across multiple asynchronous calls (like we share &lt;code&gt;customerId&lt;/code&gt;) is not recommended.&lt;/p&gt;

&lt;p&gt;But &lt;code&gt;AsyncLocalStorage&lt;/code&gt; pattern comes in handy when you develop/use &lt;a href="https://smartbear.com/learn/performance-monitoring/what-is-application-performance-management/" rel="noopener noreferrer"&gt;APM Tools,&lt;/a&gt; which collect performance metrics. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.kuzzle.io/nodejs-14-asynclocalstorage-asynchronous-calls" rel="noopener noreferrer"&gt;This post&lt;/a&gt; explains how you can use &lt;code&gt;AsyncLocalStorage&lt;/code&gt; to create a simple logger component. &lt;/p&gt;

&lt;p&gt;Also NodeJS Frameworks like &lt;a href="https://adonisjs.com/" rel="noopener noreferrer"&gt;adonisjs&lt;/a&gt; uses &lt;code&gt;AsyncLocalStorage&lt;/code&gt; extensively during the HTTP requests and set the HTTP context as the state. &lt;/p&gt;

&lt;p&gt;You can read more about that &lt;a href="https://docs.adonisjs.com/guides/async-local-storage#how-does-adonisjs-uses-als" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;❤️ Appreciate your feedback and thank you very much for reading...!!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>Service Worker Caching Strategies</title>
      <dc:creator>Pahan Perera</dc:creator>
      <pubDate>Wed, 26 Jan 2022 05:47:49 +0000</pubDate>
      <link>https://dev.to/pahanperera/service-worker-caching-strategies-1dib</link>
      <guid>https://dev.to/pahanperera/service-worker-caching-strategies-1dib</guid>
      <description>&lt;p&gt;Service workers are an essential part of developing rich and powerful web applications. It provides the technical foundation to features like offline support, periodic background syncs and push notifications and eventually supports Progressive Web Apps (PWA).&lt;/p&gt;

&lt;p&gt;In order to provide great offline support, necessary resources and (sometimes) data  need to be cached within the web browser. &lt;/p&gt;

&lt;p&gt;At a high-level, a web application can have multiple levels of caching.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Service Worker Cache&lt;/strong&gt; - This is only enabled programmatically by installing a service worker into the web application. Once enabled, resources are cached using Cache Storage or IndexedDB. There are different caching strategies in this level, and we will talk more about it later in this post. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;HTTP Cache / Browser Cache&lt;/strong&gt; - Browsers tend to cache resources in the browser. If the cache has not yet expired, the browser automatically uses the cached response avoiding an external network request. However this behavior can be changed using certain response headers. &lt;br&gt;
&lt;a href="https://web.dev/http-cache/" rel="noopener noreferrer"&gt;https://web.dev/http-cache/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Server-Side Cache&lt;/strong&gt; - Network components like CDN are used to achieve this level of caching. However this does not help the offline support of your web application, but it drastically reduces content loading time over the network. &lt;br&gt;
&lt;a href="https://vercel.com/docs/concepts/edge-network/overview" rel="noopener noreferrer"&gt;https://vercel.com/docs/concepts/edge-network/overview&lt;/a&gt;  &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the content is not found in any of these levels, request will reach the origin server. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcenc2jj8ms7h4evtgab9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcenc2jj8ms7h4evtgab9.png" alt="Cache Level in a Web Application"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://web.dev/service-worker-caching-and-http-caching/" rel="noopener noreferrer"&gt;https://web.dev/service-worker-caching-and-http-caching/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this post, we will focus on different Service worker caching strategies. Each strategy will have its pros and cons and you can implement one or more strategies depending on your application characteristics. &lt;/p&gt;

&lt;p&gt;Also I have created a playground that demonstrate how each caching strategy works.&lt;/p&gt;

&lt;p&gt;Please note, that this application does not have any actual service worker implementation, and intention was to create a visualization that mimics the actual behavior. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvk5qa5lui1avablpxdna.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvk5qa5lui1avablpxdna.gif" alt="Cache Visualizer Application Demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I recommend to continue reading this post in a desktop (wide) browser, since you might not be able to properly interact with the &lt;code&gt;codesandbox&lt;/code&gt; app that is embedded in this post. &lt;/p&gt;

&lt;p&gt;Let's get started...! &lt;/p&gt;

&lt;h2&gt;
  
  
  Stale While Revalidate
&lt;/h2&gt;

&lt;p&gt;The stale-while-revalidate strategy checks the cache first and respond immediately if there is a cached response. Meanwhile a revalidation request will be initiated to the server and that new response will be cached for the future use.  &lt;/p&gt;

&lt;p&gt;This is a fairly common strategy where having the most up-to-date resource is not vital to the application.&lt;/p&gt;

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

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/sw-cache-visualizer-vw649?initialpath=/stale-while-revalidate"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developers.google.com/web/tools/workbox/modules/workbox-strategies#stale-while-revalidate" rel="noopener noreferrer"&gt;https://developers.google.com/web/tools/workbox/modules/workbox-strategies#stale-while-revalidate&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Cache First (Cache Falling Back to Network)
&lt;/h2&gt;

&lt;p&gt;If there is a cached response, that will be served immediately and network will not be used at all. But if there is no cached response, it will fall back to network to get the latest response. &lt;/p&gt;

&lt;p&gt;For assets that are non-critical, Cache First is the best option. Also this will gradually cache the responses as you use the app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs2ydn1dcsczz47zcgfgl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs2ydn1dcsczz47zcgfgl.png" alt="Cache First (Cache Falling Back to Network)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/sw-cache-visualizer-vw649?initialpath=/cache-first"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developers.google.com/web/tools/workbox/modules/workbox-strategies#cache_first_cache_falling_back_to_network" rel="noopener noreferrer"&gt;https://developers.google.com/web/tools/workbox/modules/workbox-strategies#cache_first_cache_falling_back_to_network&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Network First (Network Falling Back to Cache)
&lt;/h2&gt;

&lt;p&gt;As the first attempt, it will try to get the response from network. If it is successful, that response will be served while stored in the cache as well. If the network is not accessible, cached response is used. &lt;/p&gt;

&lt;p&gt;For requests that are updating frequently, the network first strategy is the ideal solution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff9avlgqry6ulxbi3411z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff9avlgqry6ulxbi3411z.png" alt="Network First (Network Falling Back to Cache)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/sw-cache-visualizer-vw649?initialpath=/network-first"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developers.google.com/web/tools/workbox/modules/workbox-strategies#network_first_network_falling_back_to_cache" rel="noopener noreferrer"&gt;https://developers.google.com/web/tools/workbox/modules/workbox-strategies#network_first_network_falling_back_to_cache&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Network Only
&lt;/h2&gt;

&lt;p&gt;This does not involve any cache. Always relies on the network to get the response. &lt;/p&gt;

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

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/sw-cache-visualizer-vw649?initialpath=/network-only"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developers.google.com/web/tools/workbox/modules/workbox-strategies#network_only" rel="noopener noreferrer"&gt;https://developers.google.com/web/tools/workbox/modules/workbox-strategies#network_only&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Cache Only
&lt;/h2&gt;

&lt;p&gt;Network will not be used at all. This is a less commonly used since, you have do a pre-caching step before this strategy to work.&lt;/p&gt;

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

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/sw-cache-visualizer-vw649?initialpath=/cache-only"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developers.google.com/web/tools/workbox/modules/workbox-strategies#cache_only" rel="noopener noreferrer"&gt;https://developers.google.com/web/tools/workbox/modules/workbox-strategies#cache_only&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Today we learnt about different caching levels of a web application and different caching strategies that can be used in Server Worker based caching implementation. &lt;/p&gt;

&lt;p&gt;Hope you enjoyed playing with the demo application. you can find the full app here. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/sw-cache-visualizer-vw649" rel="noopener noreferrer"&gt;https://codesandbox.io/s/sw-cache-visualizer-vw649&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to try some of these patterns, you can use the &lt;a href="https://developers.google.com/web/tools/workbox" rel="noopener noreferrer"&gt;https://developers.google.com/web/tools/workbox&lt;/a&gt; library that provides all the features out-of-the-box. &lt;/p&gt;

&lt;p&gt;As an example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;registerRoute&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;workbox-routing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;StaleWhileRevalidate&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;workbox-strategies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;registerRoute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/images/avatars/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StaleWhileRevalidate&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;❤️ Appreciate your feedback and thank you very much for reading. &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to write E2E tests in plain text using Cucumber.js</title>
      <dc:creator>Pahan Perera</dc:creator>
      <pubDate>Wed, 12 Jan 2022 05:56:55 +0000</pubDate>
      <link>https://dev.to/pahanperera/gherkin-style-e2e-tests-for-a-web-application-using-cucumberjs-4djl</link>
      <guid>https://dev.to/pahanperera/gherkin-style-e2e-tests-for-a-web-application-using-cucumberjs-4djl</guid>
      <description>&lt;p&gt;&lt;strong&gt;End-to-End (E2E) Testing&lt;/strong&gt; is a testing methodology used in software development life cycle (SDLC) to test the functionality of an application deployed as a complete system. This simulates real world user scenarios starting from frontend application, and verifies the application works as expected. After completion of this test, not only the frontend application but all the other sub-systems are validated as well.&lt;/p&gt;

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

&lt;p&gt;There are some advance, developer friendly Javascript based E2E Testing Frameworks such as &lt;a href="https://www.cypress.io/" rel="noopener noreferrer"&gt;Cypress&lt;/a&gt;, &lt;a href="https://www.protractortest.org/#/" rel="noopener noreferrer"&gt;Protractor&lt;/a&gt; and &lt;a href="https://testing-library.com/docs/react-testing-library/intro" rel="noopener noreferrer"&gt;React Testing Library&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;But &lt;a href="https://cucumber.io/" rel="noopener noreferrer"&gt;Cucumber&lt;/a&gt; is well-known for its native support for &lt;strong&gt;Behavior Driven Development (BDD)&lt;/strong&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  What is Behavior Driven Development (BDD)?
&lt;/h2&gt;

&lt;p&gt;Behavior Driven Development (BDD) is an approach that defines the behavior of an application through examples of plain text (&lt;a href="https://cucumber.io/docs/gherkin/reference/" rel="noopener noreferrer"&gt;gherkin syntax&lt;/a&gt;). At the beginning of the development, this human readable document defines the application specifications, but later it can be used as an executable that runs the E2E tests. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2zz17sjatdgl2e5412qg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2zz17sjatdgl2e5412qg.png" alt="Behavior Driven Development (BDD)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This powerful approach helps the cross functional team (marketing, product owners, developers) to create a shared understanding of the application features and minimizes the gap between technical and non-technical team members.&lt;/p&gt;

&lt;p&gt;More information about BDD&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cucumber.io/docs/bdd/" rel="noopener noreferrer"&gt;https://cucumber.io/docs/bdd/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cucumber.io/blog/bdd/getting-started-with-bdd-part-1/" rel="noopener noreferrer"&gt;https://cucumber.io/blog/bdd/getting-started-with-bdd-part-1/&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Aforementioned feature specifications are written using gherkin syntax with familiar &lt;strong&gt;Given&lt;/strong&gt;, &lt;strong&gt;When&lt;/strong&gt;, &lt;strong&gt;Then&lt;/strong&gt; format. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;

&lt;span class="kd"&gt;Feature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; Add Todo
  &lt;span class="kn"&gt;Scenario&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; add simple todo
    &lt;span class="nf"&gt;Given &lt;/span&gt;I load the TodoApp
    &lt;span class="nf"&gt;When &lt;/span&gt;I add new todo called &lt;span class="s"&gt;"Pay rent"&lt;/span&gt;
    &lt;span class="nf"&gt;Then &lt;/span&gt;I should see a &lt;span class="s"&gt;"pending"&lt;/span&gt; todo called &lt;span class="s"&gt;"Pay rent"&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Like any other E2E Testing Framework, Cucumber.js also expects an assertion library such as &lt;a href="https://nodejs.org/api/assert.html" rel="noopener noreferrer"&gt;assert&lt;/a&gt; or &lt;a href="https://www.chaijs.com/" rel="noopener noreferrer"&gt;chai&lt;/a&gt; and WebDriver for browser automation such as &lt;a href="https://www.selenium.dev/documentation/overview/" rel="noopener noreferrer"&gt;selenium-webdriver&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;In this post, I will focus on &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Installing Javascript version of Cucumber (&lt;a href="https://github.com/cucumber/cucumber-js" rel="noopener noreferrer"&gt;cucumber.js&lt;/a&gt;) on a simple Todo App written in React. &lt;/li&gt;
&lt;li&gt;Write some feature specifications in gherkin format&lt;/li&gt;
&lt;li&gt;Execute those feature specifications as E2E tests. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our final application and e2e tests configuration would look like following. &lt;/p&gt;

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

&lt;p&gt;You can also refer to my &lt;a href="https://github.com/PahanPerera/simple-todo-app-with-bdd" rel="noopener noreferrer"&gt;github project&lt;/a&gt; that has everything covering in this post. &lt;/p&gt;

&lt;p&gt;Let's get started...! &lt;/p&gt;

&lt;h3&gt;
  
  
  Create a simple web app and install cucumber.js
&lt;/h3&gt;

&lt;p&gt;You can use any web application that you have for this or create a simple app like my &lt;a href="https://github.com/PahanPerera/simple-todo-app-with-bdd" rel="noopener noreferrer"&gt;simple todo app&lt;/a&gt;.&lt;/p&gt;

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

&lt;h4&gt;
  
  
  Install dependencies
&lt;/h4&gt;

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

yarn install -D @cucumber/cucumber chromedriver selenium-webdriver


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

&lt;/div&gt;

&lt;p&gt;You might need to install an assertion library that you prefer. But to keep things simple, I am using NodeJS inbuilt &lt;a href="https://nodejs.org/api/assert.html" rel="noopener noreferrer"&gt;assert&lt;/a&gt; library.&lt;/p&gt;

&lt;p&gt;Update the scripts in package.json to run the tests as well&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"e2e"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cucumber-js e2e-tests"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;


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

&lt;/div&gt;

&lt;p&gt;Also if you want to define advance configurations you can create a &lt;a href="https://github.com/PahanPerera/simple-todo-app-with-bdd/blob/main/cucumber.js" rel="noopener noreferrer"&gt;&lt;code&gt;cucumber.js&lt;/code&gt;&lt;/a&gt; file.&lt;/p&gt;

&lt;p&gt;Also make sure the app is running at &lt;code&gt;http://localhost:3000&lt;/code&gt;, so that our e2e tests can run against that. &lt;/p&gt;

&lt;h3&gt;
  
  
  Write a Gherkin based feature specification
&lt;/h3&gt;

&lt;p&gt;Inside the &lt;code&gt;e2e-tests&lt;/code&gt; folder, add the following &lt;a href="https://github.com/PahanPerera/simple-todo-app-with-bdd/blob/main/e2e-tests/addTodo.feature" rel="noopener noreferrer"&gt;&lt;code&gt;addTodo.feature&lt;/code&gt;&lt;/a&gt; file. (&lt;code&gt;.feature&lt;/code&gt; extension is important for the cucumber.js)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;

&lt;span class="kd"&gt;Feature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; Add Todo
  &lt;span class="kn"&gt;Scenario&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; add simple todo
    &lt;span class="nf"&gt;Given &lt;/span&gt;I load the TodoApp
    &lt;span class="nf"&gt;When &lt;/span&gt;I add new todo called &lt;span class="s"&gt;"Pay rent"&lt;/span&gt;
    &lt;span class="nf"&gt;Then &lt;/span&gt;I should see a &lt;span class="s"&gt;"pending"&lt;/span&gt; todo called &lt;span class="s"&gt;"Pay rent"&lt;/span&gt;


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Write Step Definitions
&lt;/h3&gt;

&lt;p&gt;Step definitions are a code that you write to help converting gherkin based feature specification into a machine readable executables. For an example when you say &lt;code&gt;When I add new todo called "Pay rent"&lt;/code&gt;, step definitions explain what need to be done in the application. &lt;/p&gt;

&lt;p&gt;Basically it will&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find the input field to enter the todo&lt;/li&gt;
&lt;li&gt;Type "Pay rent" in that input field&lt;/li&gt;
&lt;li&gt;Find the button which saves the todo&lt;/li&gt;
&lt;li&gt;Click that button&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In High level there are two steps&lt;/p&gt;
&lt;h4&gt;
  
  
  Configure the WebDriver
&lt;/h4&gt;

&lt;p&gt;You need to configure a WebDriver so that your web application can be manupilated by the test scripts. In this example I am installing &lt;code&gt;chromedriver&lt;/code&gt; which provides the chrome driver as a NodeJS Module (NPM). &lt;/p&gt;

&lt;p&gt;Web Driver's &lt;code&gt;driver&lt;/code&gt; object can be initiated as below.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forBrowser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;chrome&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;setChromeService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setChromeOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chromeOptions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;To learn more about installing drivers, you can refer &lt;a href="https://www.selenium.dev/documentation/webdriver/getting_started/install_drivers/" rel="noopener noreferrer"&gt;this&lt;/a&gt;. &lt;/p&gt;

&lt;h4&gt;
  
  
  Write the step definitions
&lt;/h4&gt;

&lt;p&gt;You can create a &lt;a href="https://github.com/PahanPerera/simple-todo-app-with-bdd/blob/main/e2e-tests/lib/steps.js" rel="noopener noreferrer"&gt;&lt;code&gt;steps.js&lt;/code&gt;&lt;/a&gt; file inside the &lt;code&gt;e2e-tests/lib&lt;/code&gt; folder &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nc"&gt;When&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I add new todo called {string}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&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;todoText&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 1. Find the input field to enter the todo&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAddTodoInput&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="c1"&gt;// 2. Type "Pay rent" in that input field&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendKeys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todoText&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// 3. Find the button which saves the todo&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;btn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAddTodoButton&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="c1"&gt;// 4. Click that button&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;btn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&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;As you can see, step definition function can be parameterized, providing ability to create generic function that works for multiple cases. &lt;/p&gt;

&lt;p&gt;Also if you see, there are some utility functions like &lt;code&gt;this.getAddTodoInput()&lt;/code&gt; that are used to detect the UI components within your web application. You can create a &lt;a href="https://github.com/PahanPerera/simple-todo-app-with-bdd/blob/main/e2e-tests/lib/world.js" rel="noopener noreferrer"&gt;&lt;code&gt;world.js&lt;/code&gt;&lt;/a&gt; with those utility function. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;getAddTodoInput&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;addTodoInput&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;async&lt;/span&gt; &lt;span class="nf"&gt;getAddTodoButton&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;addTodoBtn&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;async&lt;/span&gt; &lt;span class="nf"&gt;getTodoCountText&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;todoCountText&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;To understand more about the &lt;code&gt;steps.js&lt;/code&gt; and &lt;code&gt;world.js&lt;/code&gt; please refer to &lt;a href="https://github.com/cucumber/cucumber-js/blob/main/docs/support_files/world.md" rel="noopener noreferrer"&gt;this&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;My goal here is to highlight some of the important areas that you need to focus on integrating cucumber.js to your next web application. Since this might be little confusing to a beginner, I really encourage you to refer to the sample application. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/PahanPerera/simple-todo-app-with-bdd" rel="noopener noreferrer"&gt;https://github.com/PahanPerera/simple-todo-app-with-bdd&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is how those low level components are stitching together to run the e2e tests&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F39xhoazau81wdbqx6hto.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F39xhoazau81wdbqx6hto.png" alt="Todo App E2E Low Level Components"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally you can run the e2e tests&lt;/p&gt;

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

yarn e2e


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

&lt;/div&gt;

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

&lt;p&gt;If you configure the HTML reporting, you can see a e2e-report.html file generated as well&lt;/p&gt;

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

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

&lt;p&gt;BDD style E2E Tests might not be a fully convenient approach for a very technical developer, But it helps when you work in cross functional team. Also implement this approach in a real world software development life cycle can be more tricky than it appears. &lt;/p&gt;

&lt;p&gt;Overall I think this is a very innovative concept that brings all the team members together and helps improving the productivity as well. &lt;/p&gt;

&lt;p&gt;In this post, I roughly touched on the initial implementation that helps you to get started with your BDD style E2E Tests with Cucumber.js, Gherkin and Selenium Web Driver. &lt;/p&gt;

&lt;p&gt;All the points that we discussed in this, can be found in this sample repo. &lt;br&gt;
&lt;a href="https://github.com/PahanPerera/simple-todo-app-with-bdd" rel="noopener noreferrer"&gt;https://github.com/PahanPerera/simple-todo-app-with-bdd&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;❤️ Appreciate your feedback and thank you for reading...&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>cucumberjs</category>
      <category>beginners</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Visual Explanation and Comparison of CSR, SSR, SSG and ISR</title>
      <dc:creator>Pahan Perera</dc:creator>
      <pubDate>Tue, 04 Jan 2022 00:25:12 +0000</pubDate>
      <link>https://dev.to/pahanperera/visual-explanation-and-comparison-of-csr-ssr-ssg-and-isr-34ea</link>
      <guid>https://dev.to/pahanperera/visual-explanation-and-comparison-of-csr-ssr-ssg-and-isr-34ea</guid>
      <description>&lt;p&gt;Hello there, &lt;/p&gt;

&lt;p&gt;&lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; is a very popular React framework and one of the beautiful features is the ability to build your web application using different rendering techniques, such as &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CSR&lt;/strong&gt; - Client Side Rendering &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSR&lt;/strong&gt; - Server Side Rendering &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSG&lt;/strong&gt; - Static Site Generation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ISR&lt;/strong&gt; - Incremental Static Regeneration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this post, I will focus on explaining and comparing these techniques using visual diagrams with minimal texts, and my goal is to create a &lt;em&gt;short note&lt;/em&gt; that you can quickly refer when needed. &lt;/p&gt;

&lt;p&gt;Having said that, this post does not cover advance technical details and code snippets, that you might want to learn as a web developer.&lt;/p&gt;

&lt;p&gt;Let's get started..!&lt;/p&gt;

&lt;h3&gt;
  
  
  Client Side Rendering
&lt;/h3&gt;

&lt;p&gt;This is what most of the web frameworks like Angular and React support out of the box. This is commonly suitable for single page applications (SPA) and applications with lot of user interactions (e.g Games) and highly dynamic content such as forms, and chat applications. &lt;/p&gt;

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

&lt;p&gt;Basically web browser will initially load an empty HTML file. Javascript and styles which are loaded after, are responsible for rendering the full user friendly page in the web browser.&lt;/p&gt;

&lt;h3&gt;
  
  
  Server Side Rendering
&lt;/h3&gt;

&lt;p&gt;Main disadvantage of CSR is that it is not Search Engine Optimized. Therefore most of the web frameworks, provide the ability to render the pages in server as well. &lt;/p&gt;

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

&lt;p&gt;Not like CSR, Each page will initiate a request to App Server, where it dynamically renders and serves full HTML for that page. Since it requests and renders the page each time user requests, page serve time is more than a CSR application. &lt;/p&gt;

&lt;h3&gt;
  
  
  Static Site Generation
&lt;/h3&gt;

&lt;p&gt;To avoid the rendering in each request, why don't we generate those files in the build time, so that we can instantly serve the pages when user requests it. &lt;/p&gt;

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

&lt;p&gt;This technique will come in handy if you want to build a web application with full of static content like a blog. One drawback is that the content might be out-of-date and your application is needed to build and deploy each time when you change the content. (in a CMS)&lt;/p&gt;

&lt;h3&gt;
  
  
  Incremental Static Regeneration
&lt;/h3&gt;

&lt;p&gt;ISR is the next improvement to SSG, where it periodically builds and revalidates the new pages so that content never gets too much out-dated. &lt;/p&gt;

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

&lt;h2&gt;
  
  
  Comparison
&lt;/h2&gt;

&lt;p&gt;To compare these four techniques, we will consider following metrics.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Build time&lt;/strong&gt; - Less value the better. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Suitable for Dynamic Content&lt;/strong&gt; - If this value is high, that technique is more suitable for applications with lot of dynamic content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Search Engine Optimization&lt;/strong&gt; - Most cases, it is best to have a good value for SEO.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Page Serve/Render Time&lt;/strong&gt; - How long it takes to render the full page in the web browser. Less value the better. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Most Recent Content&lt;/strong&gt; - Indication that it always delivers the latest content. More value the better.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Static Server / App Server&lt;/strong&gt; - Does this technique need to have a static server or an app server. Normally static servers consume lot less resources than the app servers. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8onh7r5sxmss9f87k726.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8onh7r5sxmss9f87k726.png" alt="Comparison of CSR,SSR, SSG and ISR"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some of the key thoughts are&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Page Serve/Render Time is less in CSR compared to SSR&lt;/strong&gt;, since after the initial assets load, CSR manage to load the rest of the pages very quickly. But in SSR, each page request will be served by the app server.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Page Serve/Render Time is more in ISR compare to SSG&lt;/strong&gt;, since ISR periodically requests the updated page from the server.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ISR does not have the most recent content&lt;/strong&gt;, since there can be a small window where user gets outdated content, just before the periodic content refresh. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please note that, this comparison might not be accurate based on the different perspectives that you have. Feel free to correct me as well.  &lt;/p&gt;

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

&lt;p&gt;In Highlevel, we can divide these rendering techniques into two major categories based on the level of dynamic interactions that your app has.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CSR and SSR can be used to develop highly dynamic web application and both has its pros and cons depending on the scenario.&lt;/li&gt;
&lt;li&gt;If you have a highly static content, you can use SSG or ISR. ISR is more advance and optimized, but it &lt;a href="https://vercel.com/docs/concepts/next.js/incremental-static-regeneration" rel="noopener noreferrer"&gt;requires specific platforms to work&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;❤️ Appreciate your feedback and thank you very much for reading.  &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>nextjs</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>React Micro Frontends with Webpack's Module Federation</title>
      <dc:creator>Pahan Perera</dc:creator>
      <pubDate>Tue, 21 Dec 2021 05:39:29 +0000</pubDate>
      <link>https://dev.to/pahanperera/react-micro-frontends-with-webpacks-module-federation-32ii</link>
      <guid>https://dev.to/pahanperera/react-micro-frontends-with-webpacks-module-federation-32ii</guid>
      <description>&lt;p&gt;&lt;strong&gt;Micro Frontends&lt;/strong&gt; is a very popular topic in today's frontend world. Most of the teams tend to adopt this micro frontend strategy to develop their large and complex web applications, due to many advantages it provides such as, &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Separate, decoupled codebases&lt;/li&gt;
&lt;li&gt;Independent deployment&lt;/li&gt;
&lt;li&gt;Incremental updates &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below diagram showcases some of the important concepts of micro frontends. &lt;/p&gt;

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

&lt;p&gt;Most popular way of developing micro frontends is using HTML5 Web Components (Custom Elements). Angular like web frameworks has &lt;a href="https://angular.io/guide/elements" rel="noopener noreferrer"&gt;extended to support Web Components&lt;/a&gt;, while most of other libraries like &lt;a href="https://reactjs.org/docs/web-components.html" rel="noopener noreferrer"&gt;React, supports it&lt;/a&gt; out of the box.&lt;/p&gt;

&lt;p&gt;For more information about micro frontends you can refer to &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://martinfowler.com/articles/micro-frontends.html" rel="noopener noreferrer"&gt;https://martinfowler.com/articles/micro-frontends.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://micro-frontends.org" rel="noopener noreferrer"&gt;https://micro-frontends.org&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is Module Federation in Webpack ?
&lt;/h2&gt;

&lt;p&gt;Webpack version 5 comes with a new feature called &lt;a href="https://webpack.js.org/concepts/module-federation/" rel="noopener noreferrer"&gt;Module Federation&lt;/a&gt;, which helps to share code and dependencies between projects at runtime. &lt;/p&gt;

&lt;p&gt;In high level, an application &lt;code&gt;exposes&lt;/code&gt; certain component/s via a separate javascript file, and other application that wishes to use that component, async loads that &lt;code&gt;remote&lt;/code&gt; javascript file and consume that component. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhyv0byoa6dbhv5517430.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhyv0byoa6dbhv5517430.png" alt="Webpack's Module Federation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recent times this feature has changed the way we develop micro frontends. &lt;/p&gt;

&lt;p&gt;In this post, I will walk through how you can develop React based micro frontends using Webpack's Module Federation by creating a simple bank application that shows a list of accounts and account details on a selected account. &lt;/p&gt;

&lt;p&gt;This is how our final application architecture would look like. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmlti5tc8dbz732kzw088.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmlti5tc8dbz732kzw088.png" alt="Simple Bank Application using React"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's get started..
&lt;/h2&gt;

&lt;p&gt;All of the code in this post can be found &lt;a href="https://github.com/PahanPerera/react-webpack-micro-frontends" rel="noopener noreferrer"&gt;here&lt;/a&gt; for your references. &lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;First of all, since this is about React and webpack, you should have a React application configured with Webpack.&lt;/p&gt;

&lt;p&gt;Refer to &lt;a href="https://github.com/PahanPerera/react-webpack-micro-frontends/tree/main/account-summary-app" rel="noopener noreferrer"&gt;this project&lt;/a&gt; if you need help doing that. &lt;/p&gt;

&lt;p&gt;Also, as mentioned above, we will need three React projects for our application&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;accounts-summary-app&lt;/code&gt; - Micro frontend that provides the summary of all the accounts &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;account-details-app&lt;/code&gt; - Micro frontend that provides details of a selected account&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;main-app&lt;/code&gt; - app that hosts above two components. Also acts as a medium to communicate with each other. &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Configure &lt;code&gt;ModuleFederationPlugin&lt;/code&gt; in Micro Frontend Projects
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;ModuleFederationPlugin&lt;/code&gt; is a &lt;a href="https://webpack.js.org/plugins/module-federation-plugin/" rel="noopener noreferrer"&gt;high level webpack plugin&lt;/a&gt; that provides a very convenient way to configure module federation in your projects. Also plugin comes along with webpack library without need of installing another dependency as well.&lt;/p&gt;

&lt;p&gt;Responsibility of our micro frontend projects is to &lt;code&gt;expose&lt;/code&gt; a component. So let's add following to &lt;code&gt;webpack.config.js&lt;/code&gt; of &lt;code&gt;accounts-summary-app&lt;/code&gt; project. &lt;/p&gt;

&lt;p&gt;import the plugin&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ModuleFederationPlugin&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;webpack&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;configure the plugin&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

  &lt;span class="nx"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ModuleFederationPlugin&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="s2"&gt;AccountsSummaryApp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;accountsSummaryApp_remote.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;exposes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./AccountsSummary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./src/components/AccountsSummary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;


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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt; is unique identification of your module. Normally this is the name of your micro frontend project. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;filename&lt;/code&gt; is the name of the javascript file that exposes the components&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;exposes&lt;/code&gt; is a map (key and a value) of components that are exposed from this module. (key will act as an alias for the component while the value is where the component located in the project)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let's run this project locally and see what happens. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fghnm55s4zlr57eygmxd8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fghnm55s4zlr57eygmxd8.png" alt="Separate javascript file for exposed module"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, now webpack has bundled our &lt;code&gt;AccountsSummary&lt;/code&gt; component into a separate javascript file, as we instructed in the webpack configuration. &lt;/p&gt;

&lt;p&gt;Let's do the same to the &lt;code&gt;account-details-app&lt;/code&gt; project as well&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

  &lt;span class="nx"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ModuleFederationPlugin&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="s2"&gt;AccountDetailsApp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;accountDetailsApp_remote.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;exposes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./AccountDetails&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./src/components/AccountDetails&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;In case you missed some thing, you can always refer to these two projects &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/PahanPerera/react-webpack-micro-frontends/tree/main/account-summary-app" rel="noopener noreferrer"&gt;accounts-summary-app&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/PahanPerera/react-webpack-micro-frontends/tree/main/account-details-app" rel="noopener noreferrer"&gt;account-details-app&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure &lt;code&gt;ModuleFederationPlugin&lt;/code&gt; in Host App project.
&lt;/h3&gt;

&lt;p&gt;Like I was explaining before, our host app, &lt;code&gt;main-app&lt;/code&gt; is responsible for loading the components from micro frontend projects.&lt;/p&gt;

&lt;p&gt;Like micro frontends configurations defines &lt;code&gt;exposes&lt;/code&gt;, Host app's webpack configuration defines &lt;code&gt;remotes&lt;/code&gt; that tells webpack where to find those external components. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

  &lt;span class="nx"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ModuleFederationPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;remotes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;AccountsSummaryApp_Remote&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AccountsSummaryApp@http://localhost:9001/accountsSummaryApp_remote.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;AccountDetailsApp_Remote&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AccountDetailsApp@http://localhost:9002/accountDetailsApp_remote.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;remotes&lt;/code&gt; is a map (key and value) that defines all the external modules that it consumes. Key will act as an alias for the module and value defines the remote javascript file location for that module. &lt;/p&gt;

&lt;p&gt;value should have a special format like below&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;Name of the Exposed Module&amp;gt;@&amp;lt;Remote URL of the javascript file&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now that all the webpack configurations are completed, let's write some javascript code to load external components.&lt;/p&gt;

&lt;h3&gt;
  
  
  Load External Components to Host App
&lt;/h3&gt;

&lt;p&gt;One of the beautify thing about this webpack module federation is that, developers can not feel a difference between importing a local component from its own project and remote component from an external javascript file. &lt;/p&gt;

&lt;p&gt;React code will look like you are lazy loading a component.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AccountsSummary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AccountsSummaryApp_Remote/AccountsSummary&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;and use that in your jsx&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt; &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Error while loading Account Summary&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AccountsSummary&lt;/span&gt; &lt;span class="na"&gt;onAccountSelected&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleAccountSelected&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;One thing to note about the import is that to use same alias that you define in the host application along with the component alias that you defined in your micro frontend project&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Communication between components
&lt;/h3&gt;

&lt;p&gt;As mentioned earlier, external components are same as local components in your project. So standard ways of communication should be applicable here as well.&lt;/p&gt;

&lt;p&gt;For this application, I have defined a shared state with in the host application and each component communicate via that shared state. &lt;/p&gt;

&lt;p&gt;Refer to &lt;code&gt;main-app&lt;/code&gt; to see the &lt;a href="https://github.com/PahanPerera/react-webpack-micro-frontends/blob/main/main-app/src/pages/AccountsPage.js" rel="noopener noreferrer"&gt;code&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;This is very beginner level tutorial about how to develop Micro Frontends using Webpack's Module Federation feature. During this post I was able to briefly explain about&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What are Micro Frontends&lt;/li&gt;
&lt;li&gt;What is Webpack's Module Federation Feature&lt;/li&gt;
&lt;li&gt;Configure Micro frontends to expose components&lt;/li&gt;
&lt;li&gt;Configure Host app to use those exposed components&lt;/li&gt;
&lt;li&gt;How to communicate between components&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Full working example can be found &lt;a href="https://github.com/PahanPerera/react-webpack-micro-frontends" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can find the full React Template used in this sample bank application &lt;a href="https://pahanperera.gumroad.com/l/GDJBq" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;That is all for now. Please share you feedbacks. Thank you for reading.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>microfrontends</category>
      <category>webpack</category>
      <category>react</category>
    </item>
    <item>
      <title>Implementing Light / Dark Mode in Angular</title>
      <dc:creator>Pahan Perera</dc:creator>
      <pubDate>Sun, 05 Dec 2021 06:43:37 +0000</pubDate>
      <link>https://dev.to/pahanperera/implement-light-dark-mode-in-angular-42ff</link>
      <guid>https://dev.to/pahanperera/implement-light-dark-mode-in-angular-42ff</guid>
      <description>&lt;p&gt;Light / Dark mode toggle is a very common feature in today's web applications. This feature may look very simple to the end users, but it takes some additional effort to correctly implement in a web application. &lt;/p&gt;

&lt;p&gt;This post will focus on one of the most straightforward ways of implementing dark mode, using Angular and modern CSS features.&lt;/p&gt;

&lt;p&gt;Also as a bonus, I will share a sample Angular project that has some additional features related to this. &lt;/p&gt;

&lt;p&gt;Let's get started..!&lt;/p&gt;

&lt;h3&gt;
  
  
  Why is it (little) difficult in Angular?
&lt;/h3&gt;

&lt;p&gt;In high level, A dark mode implementation requires a CSS-in-JS library so that CSS can be manipulated using Javascript. React Js like web libraries provide the flexibility to integrate any CSS-in-JS library that helps developers to implement dark mode easily. &lt;/p&gt;

&lt;p&gt;But Angular is different. Being a framework, Most of the features are handled by the framework providing limited ways to change the underlying library. Also adding to that, default view encapsulation in Angular makes it very difficult to change component's styles from outside. (Obviously that is the purpose) &lt;/p&gt;

&lt;h3&gt;
  
  
  High level Architecture
&lt;/h3&gt;

&lt;p&gt;CSS variables play an important role in this. Basically you can assign some CSS variables based on a property in the DOM (commonly a CSS &lt;code&gt;class&lt;/code&gt; in &lt;code&gt;body&lt;/code&gt;). Then you can change that property using Javascript, so that CSS variables change accordingly, affecting the child components styles as well. &lt;/p&gt;

&lt;p&gt;I will explain this using an diagram&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq4xokrkzfedpxx0u9xn7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq4xokrkzfedpxx0u9xn7.png" alt="How Light / Dark Mode works in Angular"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Firstly, set of CSS variables are defined and assigned based on the class in body element&lt;/li&gt;
&lt;li&gt;These CSS variables are used in component styles&lt;/li&gt;
&lt;li&gt;Update the class in body element to change the CSS variable assignment. Eventually affecting the component styling as well. &lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Let's do some coding..!
&lt;/h3&gt;

&lt;p&gt;First let's define some style variables in global &lt;code&gt;styles.scss&lt;/code&gt; file. (In this example I am using SCSS, but it is completed optional)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$bgColor_light&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$bgColor_dark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$textColor_light&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$textColor_dark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$borderColor_light&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$borderColor_dark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// mixin that enables css variables in light mode&lt;/span&gt;
&lt;span class="k"&gt;@mixin&lt;/span&gt; &lt;span class="nf"&gt;lighten&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;--bgColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$bgColor_light&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="na"&gt;--textColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$textColor_light&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="na"&gt;--borderColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$borderColor_light&lt;/span&gt;&lt;span class="si"&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;// mixin that enables css variables in dark mode&lt;/span&gt;
&lt;span class="k"&gt;@mixin&lt;/span&gt; &lt;span class="nf"&gt;darken&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;--bgColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$bgColor_dark&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="na"&gt;--textColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$textColor_dark&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="na"&gt;--borderColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$borderColor_dark&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Now we need to call above mixins in a conditional way. We use CSS class name in the body to determine what mixin to call. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;

&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="nc"&gt;.dark&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nd"&gt;darken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="nc"&gt;.light&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nd"&gt;lighten&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Now you can use these CSS variable to style an Angular components. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;

&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;bgColor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;textColor&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;Please make sure not to use the SCSS variables directly in your components, since those do not change once defined.&lt;/p&gt;

&lt;p&gt;Finally, let's create an Angular component that updates the CSS class in &lt;code&gt;document.body&lt;/code&gt; element programmatically. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

  &lt;span class="cm"&gt;/**
   * Function that toggles the current mode
   * Exposed publicly
   */&lt;/span&gt;
  &lt;span class="nf"&gt;toggleMode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Mode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LIGHT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Mode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DARK&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentMode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Mode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LIGHT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateCurrentMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Mode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DARK&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateCurrentMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Mode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LIGHT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;That's all. Pretty simple and straightforward. &lt;/p&gt;

&lt;h3&gt;
  
  
  Check for User's Device Preference
&lt;/h3&gt;

&lt;p&gt;Some devices provide users to set the device theme as part of system settings. So it is important that, our web application should adhere to this device theme, and load the mode appropriately. &lt;/p&gt;

&lt;p&gt;You can easily check that using following &lt;code&gt;@media&lt;/code&gt; query&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;

&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefers-color-scheme&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;But, we will be using it in your Javascript logic&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="cm"&gt;/**&lt;/span&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Init function that update the application based on the initial mode value&lt;/li&gt;
&lt;li&gt;Flow as below&lt;/li&gt;
&lt;li&gt;1 - If there is a saved mode in the browser - use this as the initial value&lt;/li&gt;
&lt;li&gt;2 - If there is no saved mode, Check for the preferred device theme&lt;/li&gt;
&lt;li&gt;3 - If device theme is dark, set the init value to &lt;code&gt;dark&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;4 - Else set the default value to &lt;code&gt;light&lt;/code&gt;
*/
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;init&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;deviceMode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;matchMedia&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;(prefers-color-scheme: dark)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;initMode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modeStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&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;initMode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;deviceMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;matches&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initMode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Mode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DARK&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="nx"&gt;initMode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Mode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LIGHT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateCurrentMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initMode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentMode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Reference Project&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;As promised, I will share the sample project that I created to demonstrate above implementation and some additional features such as &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Light / Dark Mode Toggle Button Component &lt;/li&gt;
&lt;li&gt;Angular service that can be used to implement your own toggle component&lt;/li&gt;
&lt;li&gt;Persistence via Local Storage (also ability to write other persistence methods - e.g Session Storage)&lt;/li&gt;
&lt;li&gt;Mode change listener based on RxJS Observable&lt;/li&gt;
&lt;li&gt;SCSS support with CSS variables&lt;/li&gt;
&lt;li&gt;Load initial mode based on Device Theme Preference&lt;/li&gt;
&lt;li&gt;Require no additional libraries&lt;/li&gt;
&lt;li&gt;Well documented code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9yzl793ii097uvh909oq.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9yzl793ii097uvh909oq.gif" alt="Angular Light / Dark Mode Implementation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/PahanPerera/angular-light-dark-app" rel="noopener noreferrer"&gt;Github : Angular Light / Dark App&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can find all the development information in the &lt;code&gt;README.md&lt;/code&gt; file. &lt;/p&gt;

&lt;p&gt;That is all for now. Please share you feedbacks. Thank you for reading.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>css</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
