<?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: Pere Sola</title>
    <description>The latest articles on DEV Community by Pere Sola (@petrussola).</description>
    <link>https://dev.to/petrussola</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%2F233782%2F81fd1724-ec78-4555-844f-f90fc3f5a03b.jpeg</url>
      <title>DEV Community: Pere Sola</title>
      <link>https://dev.to/petrussola</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/petrussola"/>
    <language>en</language>
    <item>
      <title>How to connect two Windows computers with a wireless LAN</title>
      <dc:creator>Pere Sola</dc:creator>
      <pubDate>Sat, 09 Nov 2024 12:15:05 +0000</pubDate>
      <link>https://dev.to/petrussola/how-to-connect-two-windows-computers-with-a-wireless-lan-6f0</link>
      <guid>https://dev.to/petrussola/how-to-connect-two-windows-computers-with-a-wireless-lan-6f0</guid>
      <description>&lt;ul&gt;
&lt;li&gt;Change profile:&lt;/li&gt;
&lt;/ul&gt;

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

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

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

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

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

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

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

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

&lt;ul&gt;
&lt;li&gt;All networks settings:&lt;/li&gt;
&lt;/ul&gt;

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

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

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

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

</description>
    </item>
    <item>
      <title>Install Simple Analytics in an Astro js project</title>
      <dc:creator>Pere Sola</dc:creator>
      <pubDate>Sat, 02 Nov 2024 17:23:31 +0000</pubDate>
      <link>https://dev.to/petrussola/install-simple-analytics-in-an-astro-js-project-2n01</link>
      <guid>https://dev.to/petrussola/install-simple-analytics-in-an-astro-js-project-2n01</guid>
      <description>&lt;ul&gt;
&lt;li&gt;There is an &lt;a href="https://github.com/simpleanalytics/astro-plugin" rel="noopener noreferrer"&gt;official package&lt;/a&gt; for that from the folks at &lt;code&gt;Simple Analytics&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Just follow the instructions and you should be good to go. It worked flawlessly for me.&lt;/li&gt;
&lt;li&gt;There is a bunch of props you can pass to it if you need configuration, you can find the docs about them &lt;a href="https://github.com/simpleanalytics/astro-plugin/blob/main/FEATURES.md" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Add the domain to your Simple Analytics dashboard. The technology detected for me was &lt;code&gt;HTML&lt;/code&gt;. After the code was deployed, it automatically detected that the script was there and it started working. Pretty cool!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>astro</category>
      <category>analytics</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Steps to fix package security vulnerabilities in your JS project</title>
      <dc:creator>Pere Sola</dc:creator>
      <pubDate>Fri, 25 Oct 2024 16:19:12 +0000</pubDate>
      <link>https://dev.to/petrussola/steps-to-fix-package-security-vulnerabilities-in-your-project-2ihk</link>
      <guid>https://dev.to/petrussola/steps-to-fix-package-security-vulnerabilities-in-your-project-2ihk</guid>
      <description>&lt;p&gt;Github sends you regular alerts when security vulnerabilities are detected among your installed packages or its dependencies. I used to try to let the &lt;code&gt;dependabot&lt;/code&gt; fix them for me. However, half the time I was not able to merge the PR that had been generated for me. As a result, the violations were left unadressed, which is not good. In my case I use &lt;code&gt;pnpm&lt;/code&gt;, I guess it is the same with &lt;code&gt;npm&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I came across &lt;a href="https://www.niraj.life/blog/understanding-npm-audit-fixing-vulnerabilities-nodejs/" rel="noopener noreferrer"&gt;this article&lt;/a&gt; by Niraj Chauhan's today and it got me into how to solve them using the terminal.&lt;/p&gt;

&lt;p&gt;Steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You get the dependabot alert from Github:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;I know, the package name in the screenshot above doesn't match the rest of the article. But this is about the steps, you get the point.&lt;/li&gt;
&lt;li&gt;Navigate to the project in your machine and run &lt;code&gt;pnpm audit&lt;/code&gt;. You should see details about the vulnerabilities:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;In the path section you should see what is causing this. In my case, it seems to be "nested dependencies" (dependencies of dependencies). &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can run &lt;code&gt;pnpm why NAME_OF_THE_PACKAGE&lt;/code&gt; to confirm the above. In my case, I get this when running it on my first vulnerability: &lt;code&gt;pnpm why netmask&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You can try running &lt;code&gt;pnpm audit fix&lt;/code&gt; but it never works for me. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open your &lt;code&gt;package.json&lt;/code&gt; and update the package version that is causing this - in my case &lt;code&gt;mailgun-js&lt;/code&gt;. You can run &lt;code&gt;pnpm view NAME_OF_THE_PACKAGE versions&lt;/code&gt; to see all the versions or &lt;code&gt;pnpm info NAME_PACKAGE version&lt;/code&gt; to know the latest stable version.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If it is different, edit your package.json file with the version you need and run &lt;code&gt;pnpm i&lt;/code&gt; again. After that you run &lt;code&gt;pnpm audit&lt;/code&gt; again to confirm that the vulnerability is gone. If it is still there, start again or continue reading.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;In my case, the latest stable version is the one I have installed, so I need to take another approach.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We can force pnpm to install a certain version of a nested dependency. The &lt;a href="https://pnpm.io/package_json" rel="noopener noreferrer"&gt;pnpm docs&lt;/a&gt; are here and you do it like so in your package.json file:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhxingho9txh8r85rrfm5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhxingho9txh8r85rrfm5.png" alt="Example of pnpm overrides code in package.json file" width="218" height="116"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I got an error about the version I was trying to override, so I wrote the latest one in my package.json file:&lt;/li&gt;
&lt;/ul&gt;

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

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

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;pnpm i&lt;/code&gt; and happy days, the vulnerability for that package is no longer there.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Edit 25/10: according to this Stackoverflow thread, both Github dependabot and &lt;code&gt;pnpm audit&lt;/code&gt; feed from the same database, so you are not missing on vulnerabilities byfixing things this way rather than the dependabot workflow. Also there is &lt;a href="https://github.blog/security/supply-chain-security/github-advisory-database-now-powers-npm-audit/" rel="noopener noreferrer"&gt;this blog post&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>security</category>
      <category>npm</category>
    </item>
    <item>
      <title>[WIP] ChatGPT API for Web Developers</title>
      <dc:creator>Pere Sola</dc:creator>
      <pubDate>Sun, 23 Jun 2024 17:03:05 +0000</pubDate>
      <link>https://dev.to/petrussola/wip-chatgpt-api-for-web-developers-9bc</link>
      <guid>https://dev.to/petrussola/wip-chatgpt-api-for-web-developers-9bc</guid>
      <description>&lt;p&gt;This post are the notes from FrontendMaster's &lt;a href="https://frontendmasters.com/courses/chatgpt-api/"&gt;course&lt;/a&gt; by Maximiliano Firtman.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>A tour of web capabilities</title>
      <dc:creator>Pere Sola</dc:creator>
      <pubDate>Wed, 03 Apr 2024 21:34:11 +0000</pubDate>
      <link>https://dev.to/petrussola/wip-a-tour-of-web-capabilities-2oac</link>
      <guid>https://dev.to/petrussola/wip-a-tour-of-web-capabilities-2oac</guid>
      <description>&lt;p&gt;This post compiles notes from Max Firtman's &lt;a href="https://frontendmasters.com/courses/device-web-apis/"&gt;course&lt;/a&gt; in Frontendmasters. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is a capability? The ability of a web browser to perform an action using typically a built-in API. Compatibility can be an issue, of course. So some of the capabilities may not be available in some browsers. &lt;/li&gt;
&lt;li&gt;Maturity of the capabilities: green (mature), light-green (may not be available in every browse. Normally chromium-based browsers vs Firefox/Safari), yellow (not mature and only available in some browsers), red (you can't use them and may be added in the long term).&lt;/li&gt;
&lt;li&gt;Resources to check the capabilities: MDN, caniuse.com, web.dev,  webkit.org/blog (specifically for Safari), &lt;a href="https://dev.toURL"&gt;chromestatus.com&lt;/a&gt;, web.dev/baseline (multivendor, define a list of stable capabilities, stable version for the web, one list per year starting in 2022).&lt;/li&gt;
&lt;li&gt;Core capabilities NOT covered in this course: &lt;code&gt;fetch&lt;/code&gt;, &lt;code&gt;web workers&lt;/code&gt; (for threading), &lt;code&gt;WebAssembly&lt;/code&gt;, &lt;code&gt;WebSocket&lt;/code&gt;, &lt;code&gt;WebRTC&lt;/code&gt;, &lt;code&gt;WebPerformance APIs&lt;/code&gt;, &lt;code&gt;Network information&lt;/code&gt; (see course &lt;a href="https://frontendmasters.com/courses/web-app-performance/"&gt;here&lt;/a&gt;), Device memory, WebOTP (one-time password), Web Crypto (cryptography), storage (another &lt;a href="https://frontendmasters.com/courses/web-storage-apis/"&gt;course&lt;/a&gt;), Web Components, CSS, 2D Canvas, WebGL, Pointer Lock (for gaming), screen capture, PWA (&lt;a href="https://frontendmasters.com/courses/pwas/"&gt;course&lt;/a&gt;), page visibility, background sync, background fetch, web push, and notifications, media session (all these in the &lt;a href="https://frontendmasters.com/courses/background-javascript/"&gt;course&lt;/a&gt;), Web Authentication, passkeys, credential management, (all these in the &lt;a href="https://frontendmasters.com/courses/web-auth-apis/"&gt;course&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Permissions: some are harmless, others have a privacy risk or have a cost. If there is a cost or risk some browsers may limit it: user engagement requirements or permission dialog to the user. Most will require HTTPS. Some capabilities will need the user interaction to be enabled (aka you can't trigger it on page load). Permissions are granted on an origin base (domain). If the user denies permission, the API won't be able to ask again, manual re-enablement is required. Permission may have no time limit or it may be limited by time or session or usage. They are enabled for the main navigation (the HTML document that was loaded) - it won't be available for iframes. If you want to turn a capability off: permission policy spec, it's an HTTP header (&lt;code&gt;Permissions-Policy&lt;/code&gt;), for an iframe it's an HTML attribute.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Capabilities
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Permissions API
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Permissions API.
&lt;/h4&gt;

&lt;p&gt;MDN Docs &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Sensors, Geolocation, and Input Devices
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Sensors on mobile devices: accelerometer (3 axis - x, z, y), gyroscope (turning the phone - alpha, beta, gamma), magnetometer (compass), proximity (to the user), light sensor.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  2. Two ways to consume them on the web: old APIs (global DOM APIs, that is how you need to do it in iPhones and iPads. It only supports magnetometer, gyroscope, and accelerometer. Done with event listeners. i.e. &lt;code&gt;devicemotion&lt;/code&gt; and &lt;code&gt;deviceorientation&lt;/code&gt; (MDN docs &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/devicemotion_event"&gt;here&lt;/a&gt;) and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/deviceorientation_event"&gt;here&lt;/a&gt;. They need user permission), Sensor API (not yet in Safari nor Firefox, see &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Sensor_APIs#browser_compatibility"&gt;MDN&lt;/a&gt;).
&lt;/h4&gt;

&lt;h4&gt;
  
  
  3. Geolocation API (one of the first capabilities on the web).
&lt;/h4&gt;

&lt;p&gt;Google, Apple, etc. know your location because of WiFi - your devices know which WiFis are around and these companies can locate you because they have a database of SSIDs and their location. The API will give you the location, it's provider-agnostic (wifi, GPS, etc.). Works only in the foreground - won't work in the background/workers. Since the API is old, it's callback-based (no promises). MDN docs &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;h4&gt;
  
  
  4. Screen orientation API.
&lt;/h4&gt;

&lt;p&gt;Green availability: if the device is in &lt;code&gt;portrait&lt;/code&gt; or &lt;code&gt;landscape&lt;/code&gt; mode. Other stuff is not yet widely available: &lt;code&gt;lock&lt;/code&gt; the screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw3ftvjvtjgf3atzushdd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw3ftvjvtjgf3atzushdd.png" alt="Image description" width="771" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  5. Touch events API.
&lt;/h4&gt;

&lt;p&gt;They work with touch screens: &lt;code&gt;touchstart&lt;/code&gt;, &lt;code&gt;touchend&lt;/code&gt;, &lt;code&gt;touchcancel&lt;/code&gt;, etc. Apple proprietary. MDN docs &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Touch_events#browser_compatibility"&gt;here&lt;/a&gt;. That is why the following API was created:&lt;/p&gt;

&lt;h4&gt;
  
  
  6. Pointer events API.
&lt;/h4&gt;

&lt;p&gt;MDN docs &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events"&gt;here&lt;/a&gt;. Based on mouse events, and multi-pointer (they work with mouse, trackpad, touch pen, stylus, etc). YOu receive one event per touch interaction (ie. 3 fingers you get 3 events vs 1 event in touch event API above). &lt;/p&gt;

&lt;h4&gt;
  
  
  7. VirtualKeyboard API.
&lt;/h4&gt;

&lt;p&gt;MDN docs &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/VirtualKeyboard_API"&gt;here&lt;/a&gt;. This API lets us show/hide the virtual keyboard and know how much space it is taking in the screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5pg3k8eyqxjj9vclg7de.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5pg3k8eyqxjj9vclg7de.png" alt="Image description" width="768" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  8. Gamepad API.
&lt;/h4&gt;

&lt;p&gt;MDN docs &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Gamepad_API/Using_the_Gamepad_API"&gt;here&lt;/a&gt;. Greenlight API. High-level API (I don't need to know the specifics of the gamepad, and it's the minimum that all gamepads have i.e. if a gamepad has a speaker that is not common, so it is not supported via the API) and low latency. You create a requestAnimationFrame loop (60 fps) and you check the status of each button with a &lt;code&gt;boolean&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F88pbjw43zd8p7wi32i6d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F88pbjw43zd8p7wi32i6d.png" alt="Image description" width="769" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  9. Web HID API (HID = Human Interface Device).
&lt;/h4&gt;

&lt;p&gt;MDN docs &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/WebHID_API"&gt;here&lt;/a&gt;. Limited availability (light-green). &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9v8mggtda0i3ebwa0foe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9v8mggtda0i3ebwa0foe.png" alt="Image description" width="795" height="497"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsmnymp0z4sed7l0a1lvj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsmnymp0z4sed7l0a1lvj.png" alt="Image description" width="765" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Speech, voice, and camera
&lt;/h3&gt;

&lt;h4&gt;
  
  
  10. Web Speech API.
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Speech recognition API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;MDN docs &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyhvtmvm8m1cdxfqrugya.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyhvtmvm8m1cdxfqrugya.png" alt="Image description" width="769" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Speech synthesis API.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can make the web app speak.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwb0mklanfwhqh7zztjwl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwb0mklanfwhqh7zztjwl.png" alt="Image description" width="767" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  11. Shape detection API. Between yellow and red.
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Barcode detector API. MDN docs &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/BarcodeDetector"&gt;here&lt;/a&gt;. Experimental, it is only available for Chrome on Android as of this writing. Chromestatus &lt;a href="(https://developer.mozilla.org/en-US/docs/Web/API/BarcodeDetector)"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbcdopt9tuq6fel75nx94.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbcdopt9tuq6fel75nx94.png" alt="Image description" width="763" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Face detector API. Experimental, it is only available for Chrome on Android as of this writing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3mi61qofuqabswi7v0l2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3mi61qofuqabswi7v0l2.png" alt="Image description" width="763" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Text detector API (OCR). Experimental, it is only available for Chrome on Android as of this writing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr8ol0js44c9svrozrwdn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr8ol0js44c9svrozrwdn.png" alt="Image description" width="759" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  12. Media devices. It lets you open the camera and microphone, and get the stream.
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ld61mvqjeax7pp6w43d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ld61mvqjeax7pp6w43d.png" alt="Image description" width="763" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  13. Advanced control camera (aka Camera PTZ - Pan, Tilt, Zoom). Let's you manipulate the camera.
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F06kdxh89hz257lhc4mrx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F06kdxh89hz257lhc4mrx.png" alt="Image description" width="754" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  13. Augmented reality (AR, XR).
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqv29x9c7tqvydpgdzlmc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqv29x9c7tqvydpgdzlmc.png" alt="Image description" width="751" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvwbz2ue6pv51wcymut27.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvwbz2ue6pv51wcymut27.png" alt="Image description" width="761" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  14. Screen Wake Lock API. MDN docs &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Screen_Wake_Lock_API"&gt;here&lt;/a&gt;. Light green (not supported on Safari on iOS).
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fid17kapeev482xzzzg44.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fid17kapeev482xzzzg44.png" alt="Image description" width="745" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  External hardware and Devices
&lt;/h3&gt;

&lt;h4&gt;
  
  
  15. Web Bluetooth API. Limited availability. MDN docs &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Bluetooth_API"&gt;here&lt;/a&gt;. FF and Safari don't implement it and looks like they will never do it, because of reasons. So only on Chromium-based browsers for now. Only with BLE devices (Bluetooth Low Energy).
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0me2cw8npesjz41328t5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0me2cw8npesjz41328t5.png" alt="Image description" width="764" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxgjs3jo7en116z038u2e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxgjs3jo7en116z038u2e.png" alt="Image description" width="752" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  16. Web Audio API. MDN docs &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API"&gt;here&lt;/a&gt;. Green. Low-level API that lets you generate dynamic audio, 3D audio, and ultrasound communication with devices. Sonic socket &lt;a href="https://smus.com/ultrasonic-networking/"&gt;library&lt;/a&gt; for ultrasound communication between devices.
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxt2anbwgjf59waa6hz95.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxt2anbwgjf59waa6hz95.png" alt="Image description" width="750" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe307g51qg54x7owgr0bu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe307g51qg54x7owgr0bu.png" alt="Image description" width="742" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  17. Web Midi API. MDN docs &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_MIDI_API"&gt;here&lt;/a&gt;. Limited availability (Chromium-based browsers only). It's similar but much older than HID.
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh8oslv78eq96d1tbfhwx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh8oslv78eq96d1tbfhwx.png" alt="Image description" width="740" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvqpqegajg64i8g5ia13y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvqpqegajg64i8g5ia13y.png" alt="Image description" width="740" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  18. Web serial API. Very low level API. MDN docs &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API"&gt;here&lt;/a&gt;. Experimental.
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fem7t5zonzuq5f40p5jxk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fem7t5zonzuq5f40p5jxk.png" alt="Image description" width="750" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  19. Web USB API. MDN docs &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/WebUSB_API"&gt;here&lt;/a&gt;. Experimental. Low-level API for device vendors. You probably won't be using this API.
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8k9exobuoxu17jm25m1l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8k9exobuoxu17jm25m1l.png" alt="Image description" width="744" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  19. Vibration API. MDN docs &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Vibration_API"&gt;here&lt;/a&gt;. Targeting phones only.
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fokze2h5my5apokrxa1rz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fokze2h5my5apokrxa1rz.png" alt="Image description" width="744" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  20. Battery status. MDN docs &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Battery_Status_API#browser_compatibility"&gt;here&lt;/a&gt;. Doesn't work in many browsers.
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fboqt4jtu336ook6z1abq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fboqt4jtu336ook6z1abq.png" alt="Image description" width="745" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  21. Idle detection. MDN docs &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Idle_Detection_API"&gt;here&lt;/a&gt;. Limited availability.
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffygk8dm18vl2p6na1nig.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffygk8dm18vl2p6na1nig.png" alt="Image description" width="747" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  22. Web NFC. MDN docs &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_NFC_API"&gt;here&lt;/a&gt;. Limited availability.
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft2r84ya3g7n498mrg1yn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft2r84ya3g7n498mrg1yn.png" alt="Image description" width="787" height="493"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4cggc2sor5ycxdqmo5sn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4cggc2sor5ycxdqmo5sn.png" alt="Image description" width="764" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
    </item>
    <item>
      <title>Testing fundamentals</title>
      <dc:creator>Pere Sola</dc:creator>
      <pubDate>Sat, 09 Mar 2024 16:51:08 +0000</pubDate>
      <link>https://dev.to/petrussola/testing-fundamentals-42hh</link>
      <guid>https://dev.to/petrussola/testing-fundamentals-42hh</guid>
      <description>&lt;p&gt;Some notes from the Frontendmasters' workshop &lt;code&gt;Testing Fundamentals&lt;/code&gt; by Miško Hevery.&lt;/p&gt;

&lt;h3&gt;
  
  
  Theory
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;We test because it is the path of least resistance.&lt;/li&gt;
&lt;li&gt;Micro development model: develop - test - develop - test, etc. The question becomes: are tests are automated?&lt;/li&gt;
&lt;li&gt;The magic of testing is how I design my code so it is easy to test. It is not about the tools or knowledge. &lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Kind of tests
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Testing level: unit tests, integration tests (functional), system test (e2e), acceptance tests.&lt;/li&gt;
&lt;li&gt;Automation: automated tests, manual tests.&lt;/li&gt;
&lt;li&gt;Functionality: functional, performance, security, usability, a11y. &lt;/li&gt;
&lt;li&gt;Other: regression (add tests when a bug is found and fixed to avoid the regression again), smoke (large system but running all tests takes hours, so you select a subset of tests for a sanity check).&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h4&gt;
  
  
  Unit testing (tools, TDD, mocking, dependencies, coverage, benchmark)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;They use &lt;code&gt;vitest&lt;/code&gt; in the course, but I guess it is a similar test runner to say &lt;code&gt;jest&lt;/code&gt; syntax-wise.&lt;/li&gt;
&lt;li&gt;You may have a function to test that calls an external service. It would work if you make the api call in the test, but it will get expensive (what if you are testing a card transaction..) and flaky (what if the service is down..). So &lt;code&gt;mocking&lt;/code&gt; is like inserting a collaborator on the other side of the api call that returns the stuff you want for your test.&lt;/li&gt;
&lt;li&gt;So to test &lt;code&gt;fetch&lt;/code&gt;, instead of importing and calling it in the function, you pass it to the function so you can mock that function. Like:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const functionToTest = async (arg1, fetch) =&amp;gt; {
    const response = await fetch(whatever)

    return response
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the test will have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;it('whatever', async () =&amp;gt; {
    // This is the "pretend" fetch, but it doesn't know what to do yet
    const mockFetch = jest.fn&amp;lt;Type&amp;gt;()

    const response = functionToTest(whatever, mockFetch)

    expect(response).toWhatever()
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;You can do &lt;code&gt;it.todo()&lt;/code&gt; while you are writting tests, they won't error out.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;expect(object).toMatchObject(anotherObj)&lt;/code&gt; I think it is similar to the &lt;code&gt;expect.objectContain(anotherObj)&lt;/code&gt;. &amp;lt;&amp;lt; TBD, I forgot the exact syntax.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Integration testing
&lt;/h4&gt;

&lt;h4&gt;
  
  
  Component testing (UI)
&lt;/h4&gt;

&lt;h4&gt;
  
  
  E2E testing
&lt;/h4&gt;

</description>
    </item>
    <item>
      <title>Accessibility for the web</title>
      <dc:creator>Pere Sola</dc:creator>
      <pubDate>Sun, 25 Feb 2024 17:48:44 +0000</pubDate>
      <link>https://dev.to/petrussola/a11y-for-the-web-55oa</link>
      <guid>https://dev.to/petrussola/a11y-for-the-web-55oa</guid>
      <description>&lt;p&gt;&lt;em&gt;Photo by &lt;a href="https://unsplash.com/@hannahbusing?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash"&gt;Hannah Busing&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/person-in-red-sweater-holding-babys-hand-Zyx1bK9mqmA?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;These are my notes from the excellent two Frontendmasters' courses about accessibility, by &lt;a href="https://frontendmasters.com/courses/accessibility-v2/"&gt;Jon Kuperman&lt;/a&gt; and &lt;a href="https://frontendmasters.com/courses/react-accessibility/"&gt;Marcy Sutton&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Accessibility myth-busting
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Screen readers use JS.&lt;/li&gt;
&lt;li&gt;People use keyboards. &lt;/li&gt;
&lt;li&gt;The days of "screen-reader" skip links and other "offscreen" only skips are over, they should be made visible too.&lt;/li&gt;
&lt;li&gt;Navigating by voice is a big part of a11y.&lt;/li&gt;
&lt;li&gt;Browsers cannot detect if someone is using a screen reader.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Overlapping areas
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;SEO. a11y doesn't affect the ranking but headers do, so headers help both a11y and SEO.&lt;/li&gt;
&lt;li&gt;Add links are good for screen readers.&lt;/li&gt;
&lt;li&gt;Performance. Faster load faster interaction.&lt;/li&gt;
&lt;li&gt;Security. No a11y means a security flaw, because people cannot do it independently.&lt;/li&gt;
&lt;li&gt;Business growth. The more a11y the more people can use your website.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Standards
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.w3.org/WAI/standards-guidelines/wcag/"&gt;WCAG&lt;/a&gt; (Web Content Accessibility Group). A standard set of criteria for measuring a11y. The current version is &lt;code&gt;2.2&lt;/code&gt; (&lt;a href="https://www.w3.org/TR/WCAG22/"&gt;here&lt;/a&gt;). There is a looming 3.0 version. It is developed in open source in Github. Provides 3 conformance levels: A (lowest), AA (mid-range), and AAA (highest).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Aria&lt;/code&gt; (Accessible Rich Internet Applications) is a w3 spec (same group as CSS and HTML) and it is a set of accessibility helpers that you can apply to your HTML. The current ARIA version is &lt;code&gt;1.2&lt;/code&gt; (&lt;a href="https://www.w3.org/TR/wai-aria-1.2/"&gt;here&lt;/a&gt;) and also developed in the open, in Github. Other ARIA-related non-normative documents (informative): &lt;a href="https://www.w3.org/TR/html-aria/"&gt;ARIA in HTML&lt;/a&gt; and &lt;a href="https://www.w3.org/TR/using-aria/"&gt;Using ARIA&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://webaim.org/"&gt;WebAIM&lt;/a&gt; - Web Accessibility In Mind. They provide a &lt;a href="https://webaim.org/standards/wcag/checklist"&gt;checklist&lt;/a&gt;. It is not an official spec but rather a way to make the WCAG specs more digestible.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Screen readers
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Type of &lt;code&gt;AT&lt;/code&gt; (Assistive Technology), both software and hardware. They convert text and graphic images to speech or Braille output.&lt;/li&gt;
&lt;li&gt;iPhones and Macs have screen readers built in (VoiceOver). On Windows, users can use the built-in screen reader &lt;code&gt;Narrator&lt;/code&gt; or install &lt;code&gt;NVDA&lt;/code&gt; or &lt;code&gt;JAWS&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;There are many combinations and we can't test them all. &lt;code&gt;WebAIM&lt;/code&gt; runs a survey every couple of years where you can see the most popular screen-readers for each platform. You can focus on these.&lt;/li&gt;
&lt;li&gt;VoiceOver keyboard &lt;a href="https://dequeuniversity.com/screenreaders/voiceover-keyboard-shortcuts"&gt;cheatsheet&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.nvaccess.org/"&gt;NVDA&lt;/a&gt; for Windows (free), Chrome screen reader, Voiceover for Mac.&lt;/li&gt;
&lt;li&gt;Images. &lt;code&gt;alternative text&lt;/code&gt;. The screen reader will read the file name if it doesn't find an &lt;code&gt;alt text&lt;/code&gt;. Alt text will override this behavior. &lt;code&gt;alt=""&lt;/code&gt; is empty alt text and the screen reader will not read it. This is useful if you have decorative images. Screen readers will ignore images in a CSS background. The alt text should be brief and descriptive. Lacking alt text is one of the top 5 a11y issues. &lt;a href="https://www.w3.org/WAI/tutorials/images/decision-tree/"&gt;Alt decision tree&lt;/a&gt; will help you decide if and what to write in the alt text.&lt;/li&gt;
&lt;li&gt;X-browser testing - &lt;a href="https://assistivlabs.com/"&gt;https://assistivlabs.com/&lt;/a&gt; can help.&lt;/li&gt;
&lt;li&gt;Audio. Needs captions. &lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Testing / Debugging
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Steps to take: &lt;/li&gt;
&lt;li&gt;STEP ONE: Tab key to navigate: can you reach and operate every interactive control? Can you see where your focus point is on the screen? Do you get trapped anywhere that you can't escape (see keyboard trapping below)? Can you use other common keys like arrows, ESC, key, and space key?&lt;/li&gt;
&lt;li&gt;STEP TWO: Open a browser devtool extension like Axa. Prioritise violations over best practices.&lt;/li&gt;
&lt;li&gt;STEP THREE: Zoom the browser to at least 200% (see reflow below).&lt;/li&gt;
&lt;li&gt;STEP FOUR: Test light and dark mode. Ensure animation and motion can be turned off with Reduced Motion (see below).&lt;/li&gt;
&lt;li&gt;STEP FIVE: Run a screen reader.&lt;/li&gt;
&lt;li&gt;STEP SIX: Make note of missing transcripts or captions and other alternative content. Ensure media players and pages can accommodate this content.&lt;/li&gt;
&lt;li&gt;Linters and dev tools: built in the browser, Chrome lighthouse, &lt;a href="https://web-accessibility-v3.vercel.app/topics/accessibility-debugging/linters-and-devtools#browser-extensions"&gt;browser extensions&lt;/a&gt;, &lt;a href="https://web-accessibility-v3.vercel.app/topics/accessibility-debugging/linters-and-devtools#eslint-and-other-text-editor-plugins"&gt;linters&lt;/a&gt;, &lt;code&gt;Accessibility&lt;/code&gt; tab in &lt;code&gt;Elements&lt;/code&gt; tab in Chrome.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Accessible HTML
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Basics always apply: HTML needs to be &lt;code&gt;valid&lt;/code&gt;, &lt;code&gt;well structured&lt;/code&gt;, and &lt;code&gt;using as many defaults as possible&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WELL STRUCTURED&lt;/code&gt;: structural semantics is very helpful in screen readers and other reader modes. Not &lt;code&gt;div&lt;/code&gt;s all over the place.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AS MANY DEFAULTS AS POSSIBLE&lt;/code&gt;. Try to use as many defaults as possible because they come with a lot of a11y behavior for free.&lt;/li&gt;
&lt;li&gt;You can do a lot by using semantic HTML. &lt;code&gt;&amp;lt;aside&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;footer&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt; don't have functionality but have semantic meaning. Others like &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt;, and &lt;code&gt;&amp;lt;textarea&amp;gt;&lt;/code&gt; provide a lot of built-in functionality. It is important to avoid generic HTML elements when more dedicated built-in elements exist. Avoid "div soup" or "divitis". &lt;/li&gt;
&lt;li&gt;HEADERS: use &lt;code&gt;h1-h6&lt;/code&gt; headings to create a page outline. Style them with CSS. Avoid the &lt;code&gt;HTML5 heading algorithm&lt;/code&gt; as it was not implemented for Assistive Tech. Use a heading based on what the content is, not how the content should look like. CSS doesn't influence screen readers. You should always use the appropriate heading and style it only if you ever need to.&lt;/li&gt;
&lt;li&gt;LANDMARK ELEMENTS: &lt;code&gt;nav&lt;/code&gt;, &lt;code&gt;main&lt;/code&gt;, &lt;code&gt;section&lt;/code&gt;, &lt;code&gt;header&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;LISTS: they are great, a screen reader will say "5 items", or whatever. Don't add other types of descendants to a list element.&lt;/li&gt;
&lt;li&gt;FORMS: very powerful elements, like &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;fieldset&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;legend&amp;gt;&lt;/code&gt;. Labels are essential for inputs/textareas/etc in Assistive Technology (AT). Explicit labels use &lt;code&gt;for&lt;/code&gt; and &lt;code&gt;id&lt;/code&gt;. Implicit labels wrap an input. Only certain elements can be labeled. &lt;/li&gt;
&lt;li&gt;HTML labels. Explicit (using &lt;code&gt;for&lt;/code&gt; attribute) or implicit (nesting input field) is the way to go. No label with &lt;code&gt;div&lt;/code&gt; or &lt;code&gt;p&lt;/code&gt;. Labels work for "labelable" items, such as: &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;keygen&amp;gt;&lt;/code&gt; (deprecated), &lt;code&gt;&amp;lt;meter&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;output&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;progress&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;textarea&amp;gt;&lt;/code&gt;. If you need to label an element not on that list, use &lt;code&gt;aria-label&lt;/code&gt; instead.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;role&lt;/code&gt;. You can use an ARIA role to indicate to the screen reader that the &lt;code&gt;div&lt;/code&gt; (or whatever other than a button) is being used as a button. Example:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div role="button" onClick="() =&amp;gt; alert('hey')"&amp;gt;Click me&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;^ This will tell the screen reader that the div can be clicked. But this won't let the div be focusable, so we have something called &lt;code&gt;tab-index&lt;/code&gt;. That means that it can be focused with the keyboard. But if you are a keyboard-only user, you won't be able to click on the element. That's why we have &lt;code&gt;onKeyUp&lt;/code&gt; (you can get precise and only listed to Enter or Spacebar. The last thing, we need an &lt;code&gt;aria-label&lt;/code&gt; to label the element.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;BUTTONS AND LINKS. HTML buttons give a lot of behavior for free: focusability, built-in-role, and keyboard click events. Links need an &lt;code&gt;href&lt;/code&gt; to be accessible. Buttons toggle things and links navigate - use them appropriately.&lt;/li&gt;
&lt;li&gt;DETAILS AND SUMMARY. Are built-in accordion-style disclosure widgets. &lt;/li&gt;
&lt;li&gt;SETTING LANGUAGE. &lt;code&gt;&amp;lt;html lang="en"&amp;gt;&lt;/code&gt;. If language is dynamic, it can be set on a template. Element level vs page level language:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;html lang="en"&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;p lang="fr"&amp;gt;&amp;lt;/p&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  ARIA
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ARIA&lt;/code&gt; stands for &lt;code&gt;Accessible Rich Internet Applications&lt;/code&gt; and it's a way to add accessibility information to your apps. As of winter 2023, the current version is &lt;code&gt;1.2&lt;/code&gt; (specs &lt;a href="https://www.w3.org/TR/wai-aria-1.2/"&gt;here&lt;/a&gt; and MDN docs &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA"&gt;here&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;ARIA and HTML work great together. Built-in roles for buttons, links, etc. (implicit roles) vs the ones we add with ARIA (bolt-on).&lt;/li&gt;
&lt;li&gt;The major categories of ARIA are &lt;code&gt;roles&lt;/code&gt;, &lt;code&gt;states&lt;/code&gt;, and &lt;code&gt;properties&lt;/code&gt;. i.e. &lt;code&gt;role="button"&lt;/code&gt; or &lt;code&gt;aria-hidden="true"&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;ROLES. Many HTML elements have roles built-in, such as &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt;. They can also be bolted on to override the default semantics of an element. &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; has the implicit &lt;code&gt;button&lt;/code&gt; role. &lt;code&gt;&amp;lt;div role="button"&amp;gt;&lt;/code&gt; has the explicit button role. You should use the native HTML element with a role built-in.&lt;/li&gt;
&lt;li&gt;ARIA attributes can be used as selectors in CSS. i.e. [role="checkbox"][aria-disabled="true"] {}&lt;/li&gt;
&lt;li&gt;You can bolt-on accessible names and descriptions using explicit ARIA attributes like &lt;code&gt;aria-label&lt;/code&gt;, &lt;code&gt;aria-labelledby&lt;/code&gt;, and &lt;code&gt;aria-describedby&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;LIVE REGIONS. It allows the screen reader to "listen" to content change in the app and read it. i.e. uber app after a ride has been booked when it changes to "looking for a driver", "driver found", "driver is here", etc. This is done with &lt;code&gt;aria-live&lt;/code&gt; and it has two values: &lt;code&gt;assertive&lt;/code&gt; (interrupts reading to read the update) or &lt;code&gt;polite&lt;/code&gt;, which will wait for the screen reader to finish reading. If it is off it will not read the update.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; is great but it only covers some elements. For the rest, you can use the following aria tools: &lt;code&gt;aria-label&lt;/code&gt;, &lt;code&gt;aria-labelledby&lt;/code&gt;, and &lt;code&gt;aria-describedby&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;aria-label&lt;/code&gt; and &lt;code&gt;aria-labelledby&lt;/code&gt; do the same but the difference is similar to the explicit and implicit label: &lt;code&gt;labelledby&lt;/code&gt; refers to an &lt;code&gt;id&lt;/code&gt; of some previous element. That element would probably have to be visually hidden or sth. &lt;code&gt;aria-describedby&lt;/code&gt; is about description, extended information that the user may need.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques"&gt;ARIA roles, states, and properties&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Focus management
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Keyboard shortcuts. You can build them for your app to help folks who are keyboard users only.&lt;/li&gt;
&lt;li&gt;Skip links. Allows you to go to main content, you can see examples in github.com or The New York Times. Create a visually hidden anchor with the body "skip to content", prepend it to the body, and give it a focus state in CSS. &lt;/li&gt;
&lt;li&gt;Tab navigation. &lt;code&gt;tab&lt;/code&gt; and &lt;code&gt;shift-tab&lt;/code&gt; to navigate forth and back in a website. Tabable elements include &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;textarea&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt;. To make a non-tabable element tabable you can use the &lt;code&gt;tab-index&lt;/code&gt; attribute to achieve so. Negative means that the element is not reachable via sequential keyboard navigation. value &lt;code&gt;0&lt;/code&gt; means it is reached by sequential tabbing and positive means that it takes priority. MDN docs &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Active element. To know which one it is (in case it is hidden or you cannot find it) you can use &lt;code&gt;document.body.addEventListener('focusin', () =&amp;gt; console.log(document.activeElement));&lt;/code&gt; in your browser console. It will print the element that has focus (active element API).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Keyboard trapping&lt;/code&gt;. Focus only on a subset of elements. The user's keyboard focus would cycle through the elements until they complete a task or close that layer (like in an accessible modal). Level A WCAG dictates that there should be no keyboard traps. &lt;a href="https://react-spectrum.adobe.com/react-aria/index.html"&gt;React-aria&lt;/a&gt; can do it for you. Also, existing design systems libraries (i.e. Chakra UI) normally have accessibility incorporated into their components. &lt;/li&gt;
&lt;li&gt;Keyboard shortcuts can be helpful. &lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Visual considerations
&lt;/h4&gt;

&lt;h5&gt;
  
  
  Color contrast
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Tools you can use: Lighthouse audit, &lt;a href="https://webaim.org/resources/contrastchecker/"&gt;WebAIM contrast checker&lt;/a&gt; for the design phase, Chrome dev tools (more info &lt;a href="https://webaim.org/articles/contrast/devtools"&gt;here&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Colors and forms. Validation errors with red/green may not work for people with disabilities. Color only is not enough, you should put some text or label.&lt;/li&gt;
&lt;li&gt;Visual impairments. Firefox extension called &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/nocoffee/"&gt;NoCoffee&lt;/a&gt;. Keeping things together helps because people may have a narrow vision field.&lt;/li&gt;
&lt;li&gt;Setting the language. In the top level &lt;code&gt;html&lt;/code&gt; and for certain text that deviates. &lt;/li&gt;
&lt;li&gt;Fix markup errors. You can use &lt;a href="https://validator.w3.org/"&gt;https://validator.w3.org/&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Reflow
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Content can be presented without loss of information or functionality, and without requiring scrolling in two dimensions for. Specs can be found &lt;a href="https://www.w3.org/TR/WCAG22/#reflow"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Reduced motion
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;prefers-reduced-motion&lt;/code&gt;. You can access the motion a11y settings from the system to change your code, like CSS animation (i.e. from pulsing to something softer).&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Color preference
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Same for the system color preference, dark or light. You can access it with:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@media (prefers-color-scheme: dark) {
     .main {
       background: black;
       color: white;
     }
}

@media (prefers-color-scheme: light) {
     .main {
       background: white;
       color: black;
     }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Tooling
&lt;/h4&gt;

&lt;h5&gt;
  
  
  Linters
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/eslint-plugin-jsx-a11y"&gt;https://www.npmjs.com/package/eslint-plugin-jsx-a11y&lt;/a&gt; for React&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Accessible Design Systems
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://react-spectrum.adobe.com/react-spectrum/"&gt;Adobe's React Spectrum&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://m3.material.io/"&gt;Google Material Design&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Accessibility Developer Tools
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;To do audits. &lt;a href="https://chromewebstore.google.com/detail/axe-devtools-web-accessib/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US"&gt;Deque&lt;/a&gt; and &lt;a href="https://developer.chrome.com/docs/lighthouse/overview/"&gt;Google's Lighthouse&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  More resources
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://learn-a11y.netlify.app/resources/"&gt;https://learn-a11y.netlify.app/resources/&lt;/a&gt; (Jon's course website)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://web-accessibility-v3.vercel.app/"&gt;https://web-accessibility-v3.vercel.app/&lt;/a&gt; (Marcy's course website)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>a11y</category>
      <category>beginners</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Functional JS</title>
      <dc:creator>Pere Sola</dc:creator>
      <pubDate>Sun, 28 Jan 2024 15:48:04 +0000</pubDate>
      <link>https://dev.to/petrussola/functional-js-464l</link>
      <guid>https://dev.to/petrussola/functional-js-464l</guid>
      <description>&lt;p&gt;I keep on forgetting some cool declarative methods in JS, so this is a reminder compilation for me to refresh my memory as I encounter them doing coding challenges.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Array.prototype.sort(compareFn)&lt;/code&gt;. Mutates array "in place" after converting values to string and comparing UTF-16 code unit values. Values are sorted ascending. If you don't want to mutate the array, use &lt;code&gt;toSorted&lt;/code&gt;. &lt;code&gt;compareFn&lt;/code&gt; is called with &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; and should return a negative number if &lt;code&gt;a&lt;/code&gt; is smaller than &lt;code&gt;b&lt;/code&gt;, positive if &lt;code&gt;a&lt;/code&gt; is bigger than &lt;code&gt;b&lt;/code&gt; or 0 if they are the same. If &lt;code&gt;compareFn&lt;/code&gt; is not supplied the array is sorted after comparing the values to their string form. More &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Math.max(value1, value2, etc.)&lt;/code&gt; and &lt;code&gt;Math.min(value1, value2, etc.)&lt;/code&gt;. If the array has few elements, you can use it like &lt;code&gt;Math.max(...array)&lt;/code&gt;. It is best to use &lt;code&gt;reduce&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const arr = [1, 2, 3];
const max = arr.reduce((a, b) =&amp;gt; Math.max(a, b), -Infinity);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;String.prototype.repeat(count)&lt;/code&gt;. Repeats a string a &lt;code&gt;count&lt;/code&gt; number of times. i.e. &lt;code&gt;'Hello'.repeat(3)&lt;/code&gt; return &lt;code&gt;HelloHelloHello&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Array.prototype.some(cb)&lt;/code&gt; - returns &lt;code&gt;true&lt;/code&gt; if one item in the array returns a truthy value when the callback is called upon or &lt;code&gt;false&lt;/code&gt; otherwise. It stops iterating as soon as it find an element that returns a truthy value.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;0 + true&lt;/code&gt; is &lt;code&gt;1&lt;/code&gt; &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_plus#usage_with_non-numbers"&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_plus#usage_with_non-numbers&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;new Set([1,1,3,2,2,3,4])&lt;/code&gt; will get rid of the duplicates and return &lt;code&gt;[1,3,2,4]&lt;/code&gt; because a &lt;code&gt;set&lt;/code&gt; can't have duplicates.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;address.split('@').pop()&lt;/code&gt; will return the domain in an email even when there are 2 &lt;code&gt;@&lt;/code&gt;s.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Regex stuff
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/^\d*/&lt;/code&gt; &amp;lt; match any series of digits at the start. You can then do &lt;code&gt;string.match(/^\d*/)&lt;/code&gt; to find a prefix made up of digits only.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;'string'.match(regex)&lt;/code&gt; will return the matches. If the &lt;code&gt;g&lt;/code&gt; flag is used, it returns an array with the matches. If not, just the first match. i.e. &lt;code&gt;'010010000110010101101100011011000110111100100001'.match(/.{1,8}/g)&lt;/code&gt; will return an array of bytes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;String.fromCharCode(charCode)&lt;/code&gt; returns the ASCII string attached to the charCode.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Binary numbers
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;parseInt(binaryNumberString, 2)&lt;/code&gt; will return the integer of the number in whatever base we say. The example is base 2.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>[WIP] The Hard Parts of UI development</title>
      <dc:creator>Pere Sola</dc:creator>
      <pubDate>Sun, 14 Jan 2024 22:59:25 +0000</pubDate>
      <link>https://dev.to/petrussola/wip-the-hard-parts-of-ui-development-pmo</link>
      <guid>https://dev.to/petrussola/wip-the-hard-parts-of-ui-development-pmo</guid>
      <description>&lt;p&gt;Notes from the course &lt;code&gt;The Hard Parts of UI Development&lt;/code&gt; by Will Sentance in &lt;a href="https://frontendmasters.com/courses/hard-parts-ui-dev/"&gt;Frontendmasters&lt;/a&gt;. &lt;/p&gt;

&lt;h4&gt;
  
  
  Goal 1 - Display content on the screen
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Layout engine&lt;/code&gt; works out page layout for specific browser/screen.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Render engine&lt;/code&gt; produces the composite ‘image’ for graphics card.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;html&lt;/code&gt; &amp;gt; &lt;code&gt;DOM&lt;/code&gt; in &lt;code&gt;C++&lt;/code&gt; (webcore) &amp;gt; visual content. &lt;code&gt;html&lt;/code&gt; is a one time addition of elements into the DOM. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CSS&lt;/code&gt; &amp;gt; &lt;code&gt;CSSOM&lt;/code&gt; (mirrors the &lt;code&gt;DOM&lt;/code&gt;) in &lt;code&gt;C++&lt;/code&gt; &amp;gt; styling the content above&lt;/li&gt;
&lt;li&gt;Render engines creates an image of the page, which gets sent to the graphics card and updated 60 times a second.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Goal 2 - Let users change the content / interact with it
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;html&lt;/code&gt; is a one time addition of elements to the &lt;code&gt;DOM&lt;/code&gt; (in C++). Changing content on the screen changes the DOM. However, we cannot run code on the DOM. Javascript is needed.&lt;/li&gt;
&lt;li&gt;When we load a url in the browser: 1) we open the html file, &lt;code&gt;html&lt;/code&gt; is parsed by the &lt;code&gt;html parser&lt;/code&gt; and creates the DOM (in C++); 2) the html file has a reference to the JS file, which will start loading by the JS engine, with its own thread of execution, memory, execution context, etc.; 3) JS links to the C++ DOM runtime via the &lt;code&gt;document&lt;/code&gt; object and all the methods available to it: &lt;code&gt;document.querySelector&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Web IDL&lt;/code&gt; (&lt;code&gt;Interface Description Language&lt;/code&gt;) - standardised way to know how to access other parts of the browser from JS. &lt;code&gt;DOM API&lt;/code&gt; is written in human language - its implementation in the browser will be described in the &lt;code&gt;Web IDL&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;const jsDiv = document.querySelector('div')&lt;/code&gt; uses the &lt;code&gt;document&lt;/code&gt; object, which will give us access to the &lt;code&gt;DOM API&lt;/code&gt; via a hidden link to the C++ DOM. It will allow us to grab a list of elements in C++. &lt;code&gt;jsDiv&lt;/code&gt; will be assigned to the evaluation of &lt;code&gt;document.querySelector('div')&lt;/code&gt;. That will be an object with properties that allow us to access and modify the C++ DOM element i.e. &lt;code&gt;textContent&lt;/code&gt;. If we console log that element, instead of the C++ DOM element we get the html command that created the C++ DOM element!&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;textContent&lt;/code&gt; is the property of &lt;code&gt;jsDiv&lt;/code&gt; in the document object that will update the DOM So it is a &lt;code&gt;getter setter&lt;/code&gt; property, otherwise it would be confined to this object and would be of little use to us. &lt;code&gt;other&lt;/code&gt; and others get added to the call stack.&lt;/li&gt;
&lt;li&gt;The following code follows the steps described after:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// in app.html
&amp;lt;input /&amp;gt;
&amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;script src='app.js'&amp;gt;&amp;lt;/script&amp;gt;

// in app.js
let post = '';

const jsInput = document.querySelector('input');
const jsDiv = document.querySelector('div');

function handleInput() {
     post = jsInput.value;
     jsDiv.textContext = post;
}

jsInput.onInput = handleInput;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;app.html&lt;/code&gt; loads; the &lt;code&gt;HTML parser&lt;/code&gt; looks at each line and adds them to the C++ DOM from which we will produce the actual pixels of the webpage through the &lt;code&gt;layout and render engine&lt;/code&gt;; the &lt;code&gt;HTML parser&lt;/code&gt; will tee up the JS engine to run; this will give us access to the &lt;code&gt;document&lt;/code&gt; object that has a reference to the C++ object, that we can run function on to search or add elements.&lt;/li&gt;
&lt;li&gt;There is a division between "C++ land" and JS land (we are not able to write code directly into the C++ land. Once the HTML is parsed and the items added in the C++ object, the items appear in the screen.&lt;/li&gt;
&lt;li&gt;When JS starts executing, we get a call stack and a global execution context, which has a pre-loaded object: &lt;code&gt;document&lt;/code&gt;. This object allow our JS to interact with the C++ object: &lt;code&gt;querySelector&lt;/code&gt; (this is one type of &lt;code&gt;accessor object&lt;/code&gt;), etc. They not only have action in JS but also in the C++ object.&lt;/li&gt;
&lt;li&gt;The JS above: 1) define const post assigned to empty string 2) &lt;code&gt;document.querySelector('input')&lt;/code&gt; will call the &lt;code&gt;querySelector&lt;/code&gt; getter/setter in the document object, which will bring us to the C++ object 3) it finds it but because the C++ object cannot be brought back a corresponding object gets produced in JS with a link to the underlying C++ object; 4) that newly produced object is assigned to &lt;code&gt;jsInput&lt;/code&gt;; 5) that JS object has properties that will allow us to work with the C++ object: i.e. &lt;code&gt;onInput&lt;/code&gt;, &lt;code&gt;value&lt;/code&gt;, etc.; 6) same for &lt;code&gt;jsDiv&lt;/code&gt;; 7) assign &lt;code&gt;handleInput&lt;/code&gt; to a function declaration; 8) in the &lt;code&gt;jsInput&lt;/code&gt; JS object representation of the C++ element we will use the setter &lt;code&gt;onInput&lt;/code&gt; to assign it to the function declaration &lt;code&gt;handleInput&lt;/code&gt;. That will add a handler in the C++ element that will trigger the execution of that function when a user inputs something in the &lt;code&gt;input&lt;/code&gt; C++ object element; 9) user action writes something in the input (ie. "Hi") and that triggers an &lt;code&gt;event&lt;/code&gt; which issues a command to the C++ element to execute its handler; 10) &lt;code&gt;value&lt;/code&gt; in the &lt;code&gt;input&lt;/code&gt; C++ element will be populated with &lt;code&gt;Hi&lt;/code&gt;; 11) the Events API will trigger the function referenced in the C++ element handler and add the call to &lt;code&gt;handleInput&lt;/code&gt; in the callback queue; 12) the &lt;code&gt;event loop&lt;/code&gt; will grab that function execution from the callback queue when the call stack is empty and there i no more JS code to run in the global execution context; 13) the function call will be added it to the &lt;code&gt;call stack&lt;/code&gt;; 14) an &lt;code&gt;execution context&lt;/code&gt; will be created with its memory; 15) in memory the variable &lt;code&gt;post&lt;/code&gt; will be assigned to the value of the property &lt;code&gt;value&lt;/code&gt; of the &lt;code&gt;jsInput&lt;/code&gt; object; 16) we look inside the &lt;code&gt;jsDiv&lt;/code&gt; object for the setter &lt;code&gt;textContext&lt;/code&gt; which is set to the value of &lt;code&gt;post&lt;/code&gt;; 17) &lt;code&gt;textContent&lt;/code&gt; updates the value of the underlying C++ element, which in turn updates the screen to show "Hi".&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  One-way data binding
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;It is a paradigm implemented by the frameworks (React, Vue, Angular, etc.) that restrict the back and forth between C++ and JS to make our lives easier as UI engineers. &lt;/li&gt;
&lt;li&gt;Code:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// in app.html
&amp;lt;input /&amp;gt;
&amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;script src='app.js'&amp;gt;&amp;lt;/script&amp;gt;

// in app.js
let post = '';

const jsInput = document.querySelector('input');
const jsDiv = document.querySelector('div');

jsInput.value = 'What is on your mind?'; // view

function handleInput() {
     post = jsInput.value;
     jsDiv.textContext = post; // affect view!
}

function handleClick() {
     jsInput.value = ''; // affect view!
}

jsInput.onInput = handleInput;
jsInput.onClick = handleClick;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;jsInput.value&lt;/code&gt; sets the C++ value to the value set in JS and that renders the string in the screen; user action click input: sends an event to the DOM to trigger the handler which adds the function to the JS callback queue; event loop grabs the &lt;code&gt;handleClick&lt;/code&gt; and adds it to the call stack; &lt;code&gt;handleClick&lt;/code&gt; is called and an execution context is created; the &lt;code&gt;value&lt;/code&gt; setter of &lt;code&gt;jsInput&lt;/code&gt; gets sets to an empty string, updates the value in the C++ element, which updates the string; next user action: input; they will write whatever, which will trigger the C++ element handler, add the function to the callback queue, event loop will add it to the call stack, new execution context, the &lt;code&gt;value&lt;/code&gt; property of the &lt;code&gt;jsInput&lt;/code&gt; object will be assigned to &lt;code&gt;post&lt;/code&gt;, and that string will be set to the &lt;code&gt;textContent&lt;/code&gt; setter, which updates the C++ element, which updates the screen.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Asynchronous JS stuff</title>
      <dc:creator>Pere Sola</dc:creator>
      <pubDate>Sun, 07 Jan 2024 21:05:54 +0000</pubDate>
      <link>https://dev.to/petrussola/asynchronous-js-53je</link>
      <guid>https://dev.to/petrussola/asynchronous-js-53je</guid>
      <description>&lt;ul&gt;
&lt;li&gt;&lt;a href="https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/"&gt;https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=8aGhZQkoFbQ"&gt;https://www.youtube.com/watch?v=8aGhZQkoFbQ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=cCOL7MC4Pl0"&gt;https://www.youtube.com/watch?v=cCOL7MC4Pl0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://frontendmasters.com/courses/javascript-hard-parts-v2/"&gt;https://frontendmasters.com/courses/javascript-hard-parts-v2/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notes from &lt;code&gt;The hard parts of asynchronous Javascript&lt;/code&gt; &lt;a href="https://frontendmasters.com/courses/javascript-new-hard-parts/"&gt;course&lt;/a&gt; in Frontendmasters, by Will Sentance. The links above are related to the topic.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When the code runs: &lt;code&gt;global execution context&lt;/code&gt;. 1) &lt;code&gt;Thread of execution&lt;/code&gt; (parsing and execution line by line) and 2) &lt;code&gt;Global Variable Environment&lt;/code&gt; (memory of variables with data).&lt;/li&gt;
&lt;li&gt;When a function gets executed, we create a new &lt;code&gt;execution context&lt;/code&gt;. 1) &lt;code&gt;thread of execution&lt;/code&gt; (go through the code in the function line by line) 2) &lt;code&gt;local memory&lt;/code&gt; (&lt;code&gt;variable environment&lt;/code&gt;) where everything in the function is stored (garbage-collected when the execution context is over).&lt;/li&gt;
&lt;li&gt;Keeping track of the execution context needs the &lt;code&gt;call stack&lt;/code&gt;. The &lt;code&gt;global execution context&lt;/code&gt; will always be at the bottom when we are running the code.&lt;/li&gt;
&lt;li&gt;Synchronicity and single threaded are two pillars of JS. How to make it asynchronous not to block the single thread?&lt;/li&gt;
&lt;li&gt;Web APIs are not part of JS (see &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction#apis_in_client-side_javascript"&gt;here&lt;/a&gt;), but allow JS to do more stuff. Web APIs are in the &lt;code&gt;web browser&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;Stuff outside JS is allowed back in (i.e. &lt;code&gt;setTimout(printHello, 1000)&lt;/code&gt;) when 1) I have finished running all my code (the &lt;code&gt;call stack&lt;/code&gt; is empty) and 2) the &lt;code&gt;call stack&lt;/code&gt; is empty. The stuff "outside" (the browser feature) gets added the the &lt;code&gt;callback queue&lt;/code&gt; (called &lt;code&gt;task queue&lt;/code&gt; in the specs) before it's allowed back in. Only when 1) and 2) are done, JS looks inside the &lt;code&gt;callback queue&lt;/code&gt; and adds it in the &lt;code&gt;call stack&lt;/code&gt;. That's called the &lt;code&gt;event loop&lt;/code&gt;. And only when the function &lt;code&gt;printHello&lt;/code&gt; is added to the call stack the code inside will run (&lt;code&gt;printHello&lt;/code&gt; doesn't run "inside" &lt;code&gt;setTimeout&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Promises&lt;/code&gt; interacts with this world outside JS but it immediately returns an object (a &lt;code&gt;Promise&lt;/code&gt; object), which acts as a placeholder of the data that will come later. The data will eventually be in the &lt;code&gt;value&lt;/code&gt; property. Promises have an &lt;code&gt;onFulfilled&lt;/code&gt; hidden property that runs when the data is available (array of functions that run when &lt;code&gt;value&lt;/code&gt; gets updated). "Two pronged" solution: JS 1) returns the &lt;code&gt;Promise&lt;/code&gt; with a placeholder and 2) initiates the browser work (xhr request). We don't know when &lt;code&gt;value&lt;/code&gt; will be filled with data, so we add functions inside the &lt;code&gt;onFulfilled&lt;/code&gt; that will run once we have the data, with &lt;code&gt;value&lt;/code&gt; as input to these functions. &lt;code&gt;.then&lt;/code&gt; adds a function to the &lt;code&gt;onFulfilled&lt;/code&gt; array. When these functions run, they are added to the &lt;code&gt;microtask queue&lt;/code&gt; (&lt;code&gt;job queue&lt;/code&gt; in the specs). The event loop prioritises tasks in the &lt;code&gt;microtask queue&lt;/code&gt; over the &lt;code&gt;callback queue&lt;/code&gt; (the &lt;code&gt;microtask queue&lt;/code&gt; should be empty before the &lt;code&gt;callback queue&lt;/code&gt; is allowed in the &lt;code&gt;call stack&lt;/code&gt;. The promise has another properties, &lt;code&gt;status&lt;/code&gt; with 3 possible values: &lt;code&gt;pending&lt;/code&gt;, &lt;code&gt;fulfilled&lt;/code&gt; and &lt;code&gt;rejected&lt;/code&gt;. The &lt;code&gt;rejected&lt;/code&gt; status will trigger a similar array to &lt;code&gt;onFulfilled&lt;/code&gt;, but called &lt;code&gt;onRejected&lt;/code&gt;. We add function there with the &lt;code&gt;.catch&lt;/code&gt; (or the 2nd argument to &lt;code&gt;.then&lt;/code&gt; (see mdn &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch"&gt;here&lt;/a&gt;). &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Closure&lt;/code&gt; === &lt;code&gt;lexical scope reference&lt;/code&gt;. &lt;code&gt;Iterator&lt;/code&gt; is a function that when called and executes something in an element it gives me the next element in the data. Iterators turn our data into "streams" of data, actual values that we can access one after another. The "closed over" data is stored in a hidden property called &lt;code&gt;[[scope]]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Generators&lt;/code&gt;. Defined with a &lt;code&gt;*&lt;/code&gt; in the function declaration (i.e. &lt;code&gt;function* createFlow() {}&lt;/code&gt;). When we call &lt;code&gt;createFlow&lt;/code&gt; (&lt;code&gt;createFlow()&lt;/code&gt;), it returns a &lt;code&gt;Generator object&lt;/code&gt; (mdn docs &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator"&gt;here&lt;/a&gt;) with a &lt;code&gt;next&lt;/code&gt; method (&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator#instance_methods"&gt;here&lt;/a&gt;), that can be called afterwards. Like the code below. Generator functions do not have arrow function counterparts.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function *createFlow() {
    yield 4;
    yield 5;
}

const returnNextElement = createFlow()
const elementOne = createFlow.next()
const elementTwo = createFlow.next()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Calling the &lt;code&gt;.next&lt;/code&gt; of a generator object creates an &lt;code&gt;execution context&lt;/code&gt;, with a local memory. When &lt;code&gt;yield&lt;/code&gt; is reached, the execution of this context is "paused". The returned value of &lt;code&gt;next&lt;/code&gt; is:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    value: 4,
    done: false, // or true if we are yielding the last value
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;When we pass values to &lt;code&gt;next&lt;/code&gt; the first &lt;code&gt;yield&lt;/code&gt; will not return any value, because of the power of the &lt;code&gt;yield&lt;/code&gt; keyword which, like &lt;code&gt;return&lt;/code&gt; kicks us out of the execution context. Next time we call &lt;code&gt;next&lt;/code&gt; with a value, the previous &lt;code&gt;yield&lt;/code&gt; will evaluate to that value, and the execution resumes. See example in the course (~17.25 in &lt;code&gt;Generator Functions with Dynamic Data&lt;/code&gt; lesson) and in &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/next#sending_values_to_the_generator"&gt;mdn&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The "backpack" (&lt;code&gt;closure&lt;/code&gt;) of the &lt;code&gt;generator&lt;/code&gt; has not also the line where execution "stopped", which allows us to continue execution when &lt;code&gt;next&lt;/code&gt; is called.&lt;/li&gt;
&lt;li&gt;In asynchronous JS (i.e. &lt;code&gt;fetch&lt;/code&gt;):
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function doWhenDataReceived(value) {
    returnNextElement.next(value);
}

function* createFlow() {
    const data = yield fetch(url);
    console.log(data);
}

const returnNextElement = createFlow();
const futureData = returnNextElement.next();

futureData.then(doWhenDataReceived)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;^ 1) Create const &lt;code&gt;returnNextElement&lt;/code&gt; to which the return value of &lt;code&gt;createFlow&lt;/code&gt; gets assigned (`&lt;code&gt;generator&lt;/code&gt; object); 2) create const &lt;code&gt;futureData&lt;/code&gt; 3) we open &lt;code&gt;createFlow&lt;/code&gt; execution context and we reach the &lt;code&gt;yield&lt;/code&gt; keywords, which "pauses" the execution of the function and allows to assign to &lt;code&gt;futureData&lt;/code&gt; the &lt;code&gt;promise&lt;/code&gt; object created by calling the &lt;code&gt;fetch&lt;/code&gt; API; 3) &lt;code&gt;.then&lt;/code&gt; adds that function to the &lt;code&gt;onFullfilled&lt;/code&gt; array in the &lt;code&gt;promise&lt;/code&gt; object (it will get triggered when the value of the promise is updated); 4) the &lt;code&gt;fetch api&lt;/code&gt; returns the data, and the function inside &lt;code&gt;onFullfulled&lt;/code&gt; gets added into the &lt;code&gt;microtask&lt;/code&gt; queue (&lt;code&gt;job queue&lt;/code&gt; officially) and, since the call stack is empty + no more code to run, it gets added into the &lt;code&gt;call stack&lt;/code&gt;; 5) &lt;code&gt;doWhenDataReceived&lt;/code&gt; execution context starts,  it calls the &lt;code&gt;.next&lt;/code&gt; from the &lt;code&gt;generator&lt;/code&gt; object, which brings us back to &lt;code&gt;createFlow&lt;/code&gt; where the execution was paused; 6) &lt;code&gt;data&lt;/code&gt; gets assigned the value of the &lt;code&gt;promise&lt;/code&gt;, and then we resume execution of the rest of the code inside that execution context.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;async&lt;/code&gt; / &lt;code&gt;await&lt;/code&gt; simplifies all this. The resumption of &lt;code&gt;createFlow&lt;/code&gt; is done automatically. But this still gets added to the microtask queue:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;br&gt;
async function createFlow() {&lt;br&gt;
    console.log("Me first");&lt;br&gt;
    const data = await fetch(url);&lt;br&gt;
    console.log(data);&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;createFlow();&lt;/p&gt;

&lt;p&gt;console.log("Me second");&lt;br&gt;
&lt;code&gt;&lt;/code&gt;`&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;await&lt;/code&gt; is similar to &lt;code&gt;yield&lt;/code&gt;, it throws you out of the execution context. 1) define &lt;code&gt;createFlow&lt;/code&gt;; 2) call &lt;code&gt;createFlow&lt;/code&gt; and open an execution context; 3) console log "me first"; 4) define &lt;code&gt;data&lt;/code&gt; variable - we don't know what it will evaluate to but the fetch creates a &lt;code&gt;promise&lt;/code&gt; object, which triggers a browser xhr request - the &lt;code&gt;promise object&lt;/code&gt; has the &lt;code&gt;value&lt;/code&gt; property and the &lt;code&gt;onFullfilled&lt;/code&gt;; 5) &lt;code&gt;await&lt;/code&gt;, like &lt;code&gt;yield&lt;/code&gt;, kicks us out of the execution context and pauses it; 6) console log "me second" runs; 7) when the data is back, the execution of &lt;code&gt;createFlow&lt;/code&gt; resumes by assigning the variable &lt;code&gt;data&lt;/code&gt; to the value of the &lt;code&gt;promise&lt;/code&gt;; 8) console log &lt;code&gt;data&lt;/code&gt;. &lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Fix Cannot GET using VSCode Live Server extension</title>
      <dc:creator>Pere Sola</dc:creator>
      <pubDate>Fri, 05 Jan 2024 16:12:16 +0000</pubDate>
      <link>https://dev.to/petrussola/fix-cannot-get-using-vscode-live-server-extension-50bm</link>
      <guid>https://dev.to/petrussola/fix-cannot-get-using-vscode-live-server-extension-50bm</guid>
      <description>&lt;ul&gt;
&lt;li&gt;I was recently working on a vanilla JS project and doing a vanilla JS client router. I was developing it using the &lt;a href="https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer"&gt;VSCode Live Server extension&lt;/a&gt;. When in a given route i.e. &lt;code&gt;/order&lt;/code&gt; and refreshing the browser page I was getting the &lt;code&gt;Cannot GET /order&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;I am not sure I would do a good job explaining why this happens (&lt;a href="https://stackoverflow.com/a/73223483/3630417"&gt;this&lt;/a&gt; SO answer does it). But I know how to fix it!&lt;/li&gt;
&lt;li&gt;Head to the vscode extension settings and set &lt;code&gt;index.html&lt;/code&gt; under the &lt;code&gt;Live Server &amp;gt; Settings: File&lt;/code&gt;. It will start working.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5dX6FIWm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5b03fim4zhkmin9tuizb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5dX6FIWm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5b03fim4zhkmin9tuizb.png" alt="Live server file setting in vscode" width="693" height="189"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vscode</category>
    </item>
    <item>
      <title>How to allow or prevent VSCode from removing the file extension in imports</title>
      <dc:creator>Pere Sola</dc:creator>
      <pubDate>Thu, 04 Jan 2024 00:05:43 +0000</pubDate>
      <link>https://dev.to/petrussola/how-to-allow-or-prevent-vscode-from-removing-the-file-extension-in-imports-1alm</link>
      <guid>https://dev.to/petrussola/how-to-allow-or-prevent-vscode-from-removing-the-file-extension-in-imports-1alm</guid>
      <description>&lt;p&gt;There is a setting called &lt;code&gt;Import Module Specifier Ending&lt;/code&gt; that you can tweak:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Es6KYfTl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sj4j8w010ibh04pg5nis.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Es6KYfTl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sj4j8w010ibh04pg5nis.png" alt="VSCode setting for Import Module Specifier Ending" width="624" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vscode</category>
    </item>
  </channel>
</rss>
