<![CDATA[Untitled RSS Feed]]>http://github.com/dylang/node-rssGatsbyJSWed, 30 Dec 2020 01:11:42 GMT<![CDATA[How much do you know about Azure CosmosDB Emulator? 🧐]]>https://yashints.dev/blog/2020/12/15/cosmos-emulatorhttps://yashints.dev/blog/2020/12/15/cosmos-emulatorTue, 15 Dec 2020 00:00:00 GMT<p><a href="https://azure.microsoft.com/en-au/services/cosmos-db/">Azure Cosmos DB</a> is one of the foundational services in Azure, which provides high availability, global scale and an impressive performance. However, it could be a bit costly for developers to spin up an instance during their development especially if they don’t know some of the basics such as what should be the partition key, what throughput they should select and so on that much. </p> <p><a href="https://docs.microsoft.com/en-us/azure/cosmos-db/local-emulator">The Azure Cosmos DB Emulator</a> is a service provided by Microsoft which allows you to emulate the Cosmos DB Service locally for development purposes. In addition, no matter whether you’re using Azure CosmosDB or not, at some point you might have to test some sort of DocumentDB locally. </p> <!--more--> <h2 id="intro" style="position:relative;"><a href="#intro" aria-label="intro permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Intro</h2> <p>Let’s be honest, there are other ways to work with Cosmos DB without paying any money such as a <a href="https://azure.microsoft.com/en-us/free/">Free Trial Account</a> which gives you <strong>$200 dollars</strong> to spend over a year, or even the <a href="https://www.documentdb.com/sql/demo">Cosmos DB Query Playground</a> which is an interactive website which helps you to learn the query syntax and provides you with a set of pre-defined JSON documents to work with.</p> <p>But eventually you either run out of money, or your product is live and your developers want to develop new features and fix bugs to be released very quickly. That’s when <em>Cosmos DB Emulator</em> really comes to the rescue. You have other advantages such as ability to work offline and or even have an Azure subscription.</p> <h2 id="features" style="position:relative;"><a href="#features" aria-label="features permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Features</h2> <h3 id="api-set" style="position:relative;"><a href="#api-set" aria-label="api set permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>API set</h3> <p>Azure Cosmos DB supports SQL API, as well as Table, MongoDB, Cassandra, and Gremlin which to me covers many scenarios from migrating an existing database from on-premise to Azure, modernising your legacy application, or create a brand new one. Azure Cosmos DB Emulator also supports these APIs although the underlying implementation details are different to the real service on Azure. In fact the emulator hides all abstractions from you and lets you focus on adding value to your team or organisation.</p> <blockquote> <p>💡 However keep in mind that the data explorer provided with the service <strong>only</strong> supports <strong>SQL API</strong> at the moment.</p> </blockquote> <h3 id="number-of-containers" style="position:relative;"><a href="#number-of-containers" aria-label="number of containers permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Number of containers</h3> <p>The emulator allows you to create a single account with multiple (up to 25 fixed sized, or 5 unlimited) containers.</p> <h3 id="operating-system" style="position:relative;"><a href="#operating-system" aria-label="operating system permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Operating System</h3> <p>At the moment, the emulator only supports 64-bit versions of Windows (Server 2012 R2, Server 2016, Server 2019, Windows 10) which demands a minimum of 2GB of RAM and 10GB of free disk space. You must also have administrative privileges to be able to install the client.</p> <p>In addition to that, it also comes with docker image which you can use to run the emulator in a docker container but only on windows containers. If you want to use docker in Linux or macOS, you will need to use it on a Windows virtual machine.</p> <h2 id="installation" style="position:relative;"><a href="#installation" aria-label="installation permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Installation</h2> <p>Simply <a href="https://aka.ms/cosmosdb-emulator">download the executable from here</a> and install it on your Windows OS, if you’re running Linux or macOS or want to run it in a docker container please refer to <a href="https://docs.microsoft.com/en-us/azure/cosmos-db/local-emulator?tabs=cli%2Cssl-netstd21#run-on-windows-docker">the official documentation</a>.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1080px; " > <a class="gatsby-resp-image-link" href="/static/4de7592b693bf405cbfca0e60aeb55dc/d8309/em.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 81.85185185185185%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAQABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAMEBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHQY5iTlIv/xAAZEAACAwEAAAAAAAAAAAAAAAAAAwEQFBP/2gAIAQEAAQUC4LM6jOki/wD/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAaEAACAgMAAAAAAAAAAAAAAAAAAjORASAy/9oACAEBAAY/AuMURrRGun//xAAZEAACAwEAAAAAAAAAAAAAAAAAARARIfH/2gAIAQEAAT8hRrHLRyhBR//aAAwDAQACAAMAAAAQXM//xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAwEBPxAJ/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAGxABAAICAwAAAAAAAAAAAAAAAQARQVEhkeH/2gAIAQEAAT8Q8HlwNgomzpzIjcAc5qWT/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Cosmos DB Emulator" title="Cosmos DB Emulator" src="/static/4de7592b693bf405cbfca0e60aeb55dc/47311/em.jpg" srcset="/static/4de7592b693bf405cbfca0e60aeb55dc/6f81f/em.jpg 270w, /static/4de7592b693bf405cbfca0e60aeb55dc/09d21/em.jpg 540w, /static/4de7592b693bf405cbfca0e60aeb55dc/47311/em.jpg 1080w, /static/4de7592b693bf405cbfca0e60aeb55dc/d8309/em.jpg 1165w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <h2 id="differences" style="position:relative;"><a href="#differences" aria-label="differences permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Differences</h2> <p>As amazing it looks, there are a few differences you need to keep in mind when working with the emulator:</p> <ul> <li>As I mentioned before the data explorer only supports the SQL API. But you can use all other APIs from within your application using the SDK.</li> <li>It only supports a single account with a well known key. You can change the key from command line, but you cannot change it in the explorer.</li> <li>For now it only supports provisioning throughput mode only, meaning you can’t use it in serverless mode.</li> <li>It does not support core features such as different consistency levels, scaling, replication and performance guaranties.</li> <li>Since the client might not be up to date with Azure Cosmos DB service, make sure you always check the <a href="https://docs.microsoft.com/en-us/azure/cosmos-db/estimate-ru-with-capacity-planner">Azure Cosmos DB capacity planner</a> to accurately estimate your required throughput.</li> <li>And the minimum ID property size is 256 characters.</li> </ul> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>In this short article I just showed you the tip of the iceberg about what the Azure Cosmos DB Emulator has to offer for you. It’s a great utility to be able to develop applications who rely on Azure Cosmos DB locally and has helped me in my pet projects which doesn’t even need to work with a Cosmos DB instance. Keep an eye out for more articles on some use cases this amazing tool can help you with.</p><![CDATA[Add dual screen support to your applications 💻]]>https://yashints.dev/blog/2020/12/07/dual-screenhttps://yashints.dev/blog/2020/12/07/dual-screenMon, 07 Dec 2020 00:00:00 GMT<p>If you have ever tried to add responsiveness to your web application you would know it’s difficult or at least takes a while to get it right. As progressive web apps (PWAs) are the first class citizens on many devices with the ability to get installed, it’s even more important to make sure user’s have the best experience possible. But technology advances in a much faster pace. We have now foldable devices like the shiny new <a href="https://devblogs.microsoft.com/surface-duo/microsoft-surface-duo-is-released/">Microsoft Surface Duo</a> which add more complexity to this equation.</p> <!--more--> <h2 id="problem" style="position:relative;"><a href="#problem" aria-label="problem permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Problem</h2> <p>What if you wanted to show your page across two screens without hiding the content under the middle edge? At least for now we don’t have any device with bending glass to be able to not worry about what appears where on the screen. </p> <p>In order to continue with this we need a demo application to make sure we’re on the same page. So let’s create one, say we have an image gallery which has 5 columns and someone is looking at it on their brand new Surface Duo:</p> <div class="gatsby-code-button-container" data-toaster-id="8544108372512382000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<div class=&quot;gallery&quot;> <div class=&quot;grid&quot;> <div class=&quot;card&quot;> <img class=&quot;card-img-top&quot; src=&quot;https://picsum.photos/200/200?random=5&quot; alt=&quot;Card image cap&quot; /> <div class=&quot;card-body&quot;> <h5 class=&quot;card-title&quot;>Card title</h5> <p class=&quot;card-text&quot;> This card has supporting text below as a natural lead-in to additional content. </p> <p class=&quot;card-text&quot;> <small class=&quot;text-muted&quot;>Last updated 3 mins ago</small> </p> </div> </div> <div class=&quot;card p-3&quot;> <img class=&quot;card-img-top&quot; src=&quot;https://picsum.photos/200/200?random=4&quot; alt=&quot;Card image cap&quot; /> <div class=&quot;card-body&quot;> <h5 class=&quot;card-title&quot;>Card title</h5> <p class=&quot;card-text&quot;> This card has supporting text below as a natural lead-in to additional content. </p> <p class=&quot;card-text&quot;> <small class=&quot;text-muted&quot;>Last updated 3 mins ago</small> </p> </div> </div> <div class=&quot;card&quot;> <img class=&quot;card-img-top&quot; src=&quot;https://picsum.photos/200/200?random=3&quot; alt=&quot;Card image cap&quot; /> <div class=&quot;card-body&quot;> <h5 class=&quot;card-title&quot;>Card title</h5> <p class=&quot;card-text&quot;> This card has supporting text below as a natural lead-in to additional content. </p> <p class=&quot;card-text&quot;> <small class=&quot;text-muted&quot;>Last updated 3 mins ago</small> </p> </div> </div> <div class=&quot;card&quot;> <img class=&quot;card-img-top&quot; src=&quot;https://picsum.photos/200/200?random=2&quot; alt=&quot;Card image cap&quot; /> <div class=&quot;card-body&quot;> <h5 class=&quot;card-title&quot;>Card title</h5> <p class=&quot;card-text&quot;> This card has supporting text below as a natural lead-in to additional content. </p> <p class=&quot;card-text&quot;> <small class=&quot;text-muted&quot;>Last updated 3 mins ago</small> </p> </div> </div> <div class=&quot;card&quot;> <img class=&quot;card-img-top&quot; src=&quot;https://picsum.photos/200/200?random=1&quot; alt=&quot;Card image cap&quot; /> <div class=&quot;card-body&quot;> <h5 class=&quot;card-title&quot;>Card title</h5> <p class=&quot;card-text&quot;> This card has supporting text below as a natural lead-in to additional content. </p> <p class=&quot;card-text&quot;> <small class=&quot;text-muted&quot;>Last updated 3 mins ago</small> </p> </div> </div> <div class=&quot;card&quot;> <img class=&quot;card-img-top&quot; src=&quot;https://picsum.photos/200/200?random=7&quot; alt=&quot;Card image cap&quot; /> <div class=&quot;card-body&quot;> <h5 class=&quot;card-title&quot;>Card title</h5> <p class=&quot;card-text&quot;> This card has supporting text below as a natural lead-in to additional content. </p> <p class=&quot;card-text&quot;> <small class=&quot;text-muted&quot;>Last updated 3 mins ago</small> </p> </div> </div> <div class=&quot;card&quot;> <img class=&quot;card-img-top&quot; src=&quot;https://picsum.photos/200/200?random=8&quot; alt=&quot;Card image cap&quot; /> <div class=&quot;card-body&quot;> <h5 class=&quot;card-title&quot;>Card title</h5> <p class=&quot;card-text&quot;> This card has supporting text below as a natural lead-in to additional content. </p> <p class=&quot;card-text&quot;> <small class=&quot;text-muted&quot;>Last updated 3 mins ago</small> </p> </div> </div> <div class=&quot;card&quot;> <img class=&quot;card-img-top&quot; src=&quot;https://picsum.photos/200/200?random=9&quot; alt=&quot;Card image cap&quot; /> <div class=&quot;card-body&quot;> <h5 class=&quot;card-title&quot;>Card title</h5> <p class=&quot;card-text&quot;> This card has supporting text below as a natural lead-in to additional content. </p> <p class=&quot;card-text&quot;> <small class=&quot;text-muted&quot;>Last updated 3 mins ago</small> </p> </div> </div> </div> </div>`, `8544108372512382000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>gallery<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>grid<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-img-top<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://picsum.photos/200/200?random=5<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Card image cap<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-body<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h5</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-title<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Card title<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h5</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> This card has supporting text below as a natural lead-in to additional content. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>small</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text-muted<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Last updated 3 mins ago<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>small</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card p-3<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-img-top<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://picsum.photos/200/200?random=4<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Card image cap<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-body<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h5</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-title<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Card title<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h5</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> This card has supporting text below as a natural lead-in to additional content. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>small</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text-muted<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Last updated 3 mins ago<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>small</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-img-top<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://picsum.photos/200/200?random=3<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Card image cap<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-body<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h5</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-title<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Card title<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h5</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> This card has supporting text below as a natural lead-in to additional content. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>small</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text-muted<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Last updated 3 mins ago<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>small</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-img-top<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://picsum.photos/200/200?random=2<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Card image cap<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-body<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h5</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-title<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Card title<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h5</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> This card has supporting text below as a natural lead-in to additional content. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>small</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text-muted<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Last updated 3 mins ago<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>small</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-img-top<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://picsum.photos/200/200?random=1<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Card image cap<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-body<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h5</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-title<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Card title<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h5</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> This card has supporting text below as a natural lead-in to additional content. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>small</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text-muted<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Last updated 3 mins ago<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>small</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-img-top<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://picsum.photos/200/200?random=7<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Card image cap<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-body<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h5</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-title<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Card title<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h5</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> This card has supporting text below as a natural lead-in to additional content. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>small</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text-muted<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Last updated 3 mins ago<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>small</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-img-top<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://picsum.photos/200/200?random=8<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Card image cap<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-body<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h5</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-title<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Card title<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h5</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> This card has supporting text below as a natural lead-in to additional content. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>small</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text-muted<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Last updated 3 mins ago<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>small</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-img-top<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://picsum.photos/200/200?random=9<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Card image cap<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-body<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h5</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-title<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Card title<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h5</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> This card has supporting text below as a natural lead-in to additional content. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card-text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>small</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text-muted<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Last updated 3 mins ago<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>small</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code></pre></div> <p>And in our CSS file we just put a 5 column layout for the card column like so:</p> <div class="gatsby-code-button-container" data-toaster-id="73705063545739250000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`.grid { display: grid; grid-template-columns: repeat(5, 1fr); grid-row: auto; }`, `73705063545739250000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">.grid</span> <span class="token punctuation">{</span> <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span> <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> <span class="token function">repeat</span><span class="token punctuation">(</span>5<span class="token punctuation">,</span> 1fr<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">grid-row</span><span class="token punctuation">:</span> auto<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div> <p>Don’t worry too much about the code, you can view the result <a href="https://pwa-dual-screen.glitch.me/">here on Glitch</a>. Now to test how this page looks like you either have to have the device handy, or if you don’t have it like me, just use the <a href="https://docs.microsoft.com/en-us/dual-screen/android/emulator/surface-duo-download?tabs=windows">Surface Duo Emulator</a> which I find really cool. For example, here is how the page looks like at the moment:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1024px; " > <a class="gatsby-resp-image-link" href="/static/5ea050377c298584b4ebdbf76110ecc0/2bef9/before.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 64.81481481481481%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAAAsSAAALEgHS3X78AAADKklEQVQ4y02TXWyTVRjH3wuvvAYjMZE4JdFoJBHYEiPcuHixkAmJJphJMq80hAXN4mAby4bNYDRON1eXQd/WUQZzw4wNMiRQaLt+YIeZOBmYSYCtxnVj/Vg/1rVv25/nHLLqk/xzno9z/jnPc/5Hczqd+LxeAoEAPr8Pj8ej4PP5CAaD3J25i8lkoqGhgenp6dJev9+vIPe5XC68fo/ABFoulyOfz1MoomAYBmtra2qVeWkjIxfRdV35qVSKrKgXi0UFaYVintSSgREvokWjUWZnZ5mfeywwx+LiEvF4nIjIR6Mx/gmHsfT20tTczHzob8JLT4jEVhRRsVAglc5QJM/ywzRLD+Jot3webCeO0H3sMMcPH+Te9B3OXRjH1G7m0tglrHad8h3l7Kio4GhrG+Mjw+jfmVkWxNLGL1/EbuvHqlu5Oj6KFnBf572db7FlSxmNBw8Q9E5Q9lIZm57bQEv9IXqcQV58v5Zte/bT/uN1brtvMilIukwtjA7Yaa3/DMfxT2n+pIr2o0fQpgIu3nzleba99jL791YxPDTI5hc2Ul35Nl/UHaDuWyvapld5dvMbVNbU8VP/adFRC3X7dtNc/zm7yrdTseEZNmoaH9fUoM09/Au9pwNrj5nvu83MzMzgdt3kF5+be/fv47txgw+r91JdtZuhgUEBGx2tX9Ld2cHY1WvYTvXR1thIW1MTY6OiZTmH+EqStWyOdcsKP72aKcUD589zxnFG+Ua+QCKZLtUMoYREMlmKNSmNhYUwIfGCSVGQUpgTr/3o0WNBnFWbTlutnDxpVn4sFmN+PiTOLChpSUWEQiGlDhlrBfH0y5EIiUSSTCajCKVcEolESWeOsw4sFovy0+k0K4Iks7qq6vISUmJyVYQymcsZKpDkErLlrBK8oUjsPzj4+psu5S9H4yw+iRKJJ0imV8U5+SmK/7W8fot15UtCOYac8ZRMH/by+jv72LrzA76yXOacc5LeK7cY9Ewx8cesOJgX7Yb5NeDh96nbTwn/j3XLi+FL6x+bZOu7tWyv/IjOs250Wx+9dhsXfr7Gb38+4MpQH6dOHKKhdg89XZ38C8fwUxxFmhnIAAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Initial state of the application across two folds" title="Initial state of the application across two folds" src="/static/5ea050377c298584b4ebdbf76110ecc0/2bef9/before.png" srcset="/static/5ea050377c298584b4ebdbf76110ecc0/01bf6/before.png 270w, /static/5ea050377c298584b4ebdbf76110ecc0/07484/before.png 540w, /static/5ea050377c298584b4ebdbf76110ecc0/2bef9/before.png 1024w" sizes="(max-width: 1024px) 100vw, 1024px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <p>You can see right away that it’s not a good look, I mean who would be willing to spend a second on this site? So how do we fix it? I think we’re now on the same page, so let’s dive in.</p> <h2 id="solution" style="position:relative;"><a href="#solution" aria-label="solution permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Solution</h2> <p>But don’t you worry, we’ve got you covered by two brand new experimental APIs that will enable you to effectively lay your elements on the screen where you want them to be.</p> <ul> <li><a href="https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/Foldables/explainer.md">CSS screen-spanning media feature</a></li> <li><a href="https://github.com/webscreens/window-segments/blob/master/EXPLAINER.md">JavaScript window segments enumeration API</a> </li> </ul> <p>The former along with a set of environment variables allows you to be aware of the geometry of the fold. The latter is an API which can be used alongside the media feature to work with non-DOM targets like Canvas 2D and WebGL. </p> <h2 id="detecting-display-regions" style="position:relative;"><a href="#detecting-display-regions" aria-label="detecting display regions permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Detecting display regions</h2> <p>As I mentioned earlier, the <code class="language-text">**screen-spanning**</code> media feature allows you to be aware of the fact that the page is spanned across multiple display regions. But how do we use it? Let’s have a look at the syntax. At its core, you will have the ability to use the below media query: </p> <div class="gatsby-code-button-container" data-toaster-id="34634355546467010000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`@media (screen-spanning: <value>) { }`, `34634355546467010000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">screen-spanning</span><span class="token punctuation">:</span> &lt;value><span class="token punctuation">)</span></span> <span class="token punctuation">{</span> <span class="token punctuation">}</span></code></pre></div> <p>The allowed values are: </p> <ul> <li><strong>single-fold-vertical</strong>: which describes the state of the viewport, when it’s spanning across a single fold and the fold’s posture is vertical. This would mean the device is in double portrait mode like below:</li> </ul> <p align="center"> <span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 450px; "> <a class="gatsby-resp-image-link" href="/static/99d6bb43a607c28986686147482caa73/20e5d/double-portrait.jpg" style="display: block" target="_blank" rel="noopener"> <span class="gatsby-resp-image-background-image" style="padding-bottom: 62.96296296296296%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAIDAQX/xAAWAQEBAQAAAAAAAAAAAAAAAAACAAH/2gAMAwEAAhADEAAAAe2s8RsKW//EABsQAAICAwEAAAAAAAAAAAAAAAABERICEBMh/9oACAEBAAEFAkvMddILwJ2P/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGBABAAMBAAAAAAAAAAAAAAAAABARMYH/2gAIAQEABj8CdjGLf//EABsQAQACAwEBAAAAAAAAAAAAAAEAESExQVFx/9oACAEBAAE/IQpiAR+ppanDiGb03KjpP//aAAwDAQACAAMAAAAQTA//xAAWEQADAAAAAAAAAAAAAAAAAAABEBH/2gAIAQMBAT8QoX//xAAXEQADAQAAAAAAAAAAAAAAAAAAARFB/9oACAECAQE/EIyrT//EABsQAQEAAwEBAQAAAAAAAAAAAAERACExUUFh/9oACAEBAAE/EGshU7lRLA35cdagvB/MrieLcciGnXuNANpO/M//2Q==&apos;); background-size: cover; display: block;"></span> <img class="gatsby-resp-image-image" alt="double portrait" title="double portrait" src="/static/99d6bb43a607c28986686147482caa73/20e5d/double-portrait.jpg" srcset="/static/99d6bb43a607c28986686147482caa73/6f81f/double-portrait.jpg 270w, /static/99d6bb43a607c28986686147482caa73/20e5d/double-portrait.jpg 450w" sizes="(max-width: 450px) 100vw, 450px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy"> </a> </span> <br> <i>Image from Microsoft Surface Duo blog</i> </p> <p>The code for this mode would be: </p> <div class="gatsby-code-button-container" data-toaster-id="7184248804865701000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`@media (screen-spanning: single-fold-vertical) { /* styles applied in double-portrait (wide) mode */ }`, `7184248804865701000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">screen-spanning</span><span class="token punctuation">:</span> single-fold-vertical<span class="token punctuation">)</span></span> <span class="token punctuation">{</span> <span class="token comment">/* styles applied in double-portrait (wide) mode */</span> <span class="token punctuation">}</span></code></pre></div> <ul> <li><strong>single-fold-horizontal</strong>: which describes the state of the viewport, when it’s spanning across a single fold but this time the posture is horizontal. This would match the double portrait tall mode like below:</li> </ul> <p align="center"> <span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 307px; "> <a class="gatsby-resp-image-link" href="/static/b917f426d014c89db872985296381bbe/6bde8/double-portrait-tall.jpg" style="display: block" target="_blank" rel="noopener"> <span class="gatsby-resp-image-background-image" style="padding-bottom: 140.74074074074073%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAcABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAECAwX/xAAWAQEBAQAAAAAAAAAAAAAAAAAAAQL/2gAMAwEAAhADEAAAAe04epoIyVZTW4Ef/8QAGxAAAgIDAQAAAAAAAAAAAAAAAAIBERASMSH/2gAIAQEAAQUCoqBS6NhORhRvJuRef//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQMBAT8BH//EABgRAAIDAAAAAAAAAAAAAAAAAAABEBEh/9oACAECAQE/AdGVH//EABsQAAICAwEAAAAAAAAAAAAAAAEQACECMXEy/9oACAEBAAY/AizRnnJHqPZRm1//xAAeEAADAAIBBQAAAAAAAAAAAAAAAREhMWEQUXGhsf/aAAgBAQABPyFI6fc4vZo/JbJbO0WTVnJk+zqKyCpyRIP/2gAMAwEAAgADAAAAEPA+g//EABcRAQEBAQAAAAAAAAAAAAAAAAABETH/2gAIAQMBAT8Q2JxqP//EABcRAAMBAAAAAAAAAAAAAAAAAAABITH/2gAIAQIBAT8QaGiqPT//xAAgEAEAAgIABwEAAAAAAAAAAAABABEhMRBRYXGR0fGx/9oACAEBAAE/EGQK3Ns6zymJ5oYWwJM/gK/Z8Y9ywFZ4dnENe5AqgV1jfifEPUocqravOf/Z&apos;); background-size: cover; display: block;"></span> <img class="gatsby-resp-image-image" alt="double portrait tall" title="double portrait tall" src="/static/b917f426d014c89db872985296381bbe/6bde8/double-portrait-tall.jpg" srcset="/static/b917f426d014c89db872985296381bbe/6f81f/double-portrait-tall.jpg 270w, /static/b917f426d014c89db872985296381bbe/6bde8/double-portrait-tall.jpg 307w" sizes="(max-width: 307px) 100vw, 307px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy"> </a> </span> <br> <i>Image from Microsoft Surface Duo blog</i> </p> <div class="gatsby-code-button-container" data-toaster-id="99407395255251530000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`@media (screen-spanning: single-fold-horizontal) { /* styles applied in double-landscape (tall) mode */ }`, `99407395255251530000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">screen-spanning</span><span class="token punctuation">:</span> single-fold-horizontal<span class="token punctuation">)</span></span> <span class="token punctuation">{</span> <span class="token comment">/* styles applied in double-landscape (tall) mode */</span> <span class="token punctuation">}</span></code></pre></div> <h2 id="environment-variables" style="position:relative;"><a href="#environment-variables" aria-label="environment variables permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Environment variables</h2> <p>To get the geometry of the device fold, you could leverage the browser environment variables. You have access to four environment variables: </p> <ul> <li>fold-top</li> <li>fold-left</li> <li>fold-width</li> <li>fold-height </li> </ul> <p>The picture below would nicely show you what there values represent:</p> <p align="center"> <span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1024px; "> <a class="gatsby-resp-image-link" href="/static/b7baf799e52328c2f552073e549b35e4/2bef9/env-variables.png" style="display: block" target="_blank" rel="noopener"> <span class="gatsby-resp-image-background-image" style="padding-bottom: 78.88888888888889%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAYAAAAWGF8bAAAACXBIWXMAAAsSAAALEgHS3X78AAACDklEQVQ4y62UfW8SQRDG+f6fQGNM/K+W2tpoCa1VoS2JFoFSSFqbJhhjEZDlXuBud2/vbh9n2bselMTY6CYPQ3iG383szm1Jaw2zTFzVn5axH+TrjBGXchh9rv8pUZA8JAVQUkIKkX0X5KYbz8hiXCoqBHyh4WViC4WxyzFyBZxAYC4jjByOiSfg8vQ+z+UaKlmpMEkt8GwQYfeS4/hG4PCa4+irwLsbiaNbiUp1hNfHDt7fRvS7XHo2h6NKcbcnsgpXgJUrgR8zDqUkQmpvKS6RJCFOPgyxvTehTiUWXIALK5OjIkGFhFolWcs50Dz5O+PgtF9+KDEPBfxAQsUSJ2djlCtT0AbCDYxnZfIMeL8f6jh9ADykNgxQSAszWvAIvu+gXv+J8oEFeplnlQF7VOHfAANBBzMZ4mPtDjsHjNIL4ILLxwNNhYyNUasNCTj9P0DPY6jlLT8GaEbh25QvT84LzIHYKCOO+ukI5be/oCM7k/6KH3AL3DiU6rXA2Jc0GopGhxTbCEg0zCmbPYSCyD1SZHzK3+9zHRVjY9+cNz0fzxoMOy2Gl81C222GJ68GeP5igL22i63mur/VnOFpw9FJkhSvnpHjuOj0rvC5dYnzdqFPrS6+dLq4uOiicd5e84yanT7uhiOdpqkF5pdDHMcQdBnwMFjTYu5jxhjYjFGcbvhGKoo2L4d/XPeXw2+IJr3W2i8Q6gAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;"></span> <img class="gatsby-resp-image-image" alt="env variables" title="env variables" src="/static/b7baf799e52328c2f552073e549b35e4/2bef9/env-variables.png" srcset="/static/b7baf799e52328c2f552073e549b35e4/01bf6/env-variables.png 270w, /static/b7baf799e52328c2f552073e549b35e4/07484/env-variables.png 540w, /static/b7baf799e52328c2f552073e549b35e4/2bef9/env-variables.png 1024w" sizes="(max-width: 1024px) 100vw, 1024px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy"> </a> </span> <br> <i>Image from Microsoft Surface Duo blog</i> </p> <h2 id="" style="position:relative;"><a href="#" aria-label=" permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h2> <p>So let’s see how we can use these features to improve our user experience a bit. First we know that we’re using the <strong><code class="language-text">single-fold-vertical</code></strong> mode, so we’ll add the relevant media query and play with the column count trying to either put the columns in the left or the right side of the fold: </p> <div class="gatsby-code-button-container" data-toaster-id="78143610197309730000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`@media (screen-spanning: single-fold-vertical) { .card-columns { grid-template-columns: repeat(4, calc( env(fold-left) /2 - 10px) ); } }`, `78143610197309730000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">screen-spanning</span><span class="token punctuation">:</span> single-fold-vertical<span class="token punctuation">)</span></span> <span class="token punctuation">{</span> <span class="token selector">.card-columns</span> <span class="token punctuation">{</span> <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> <span class="token function">repeat</span><span class="token punctuation">(</span>4<span class="token punctuation">,</span> <span class="token function">calc</span><span class="token punctuation">(</span> <span class="token function">env</span><span class="token punctuation">(</span>fold-left<span class="token punctuation">)</span> /2 - 10px<span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div> <blockquote> <p>💡 In order to access these features, you must enable experimental platform features on Edge by visiting <strong><code class="language-text">edge://flags/#enable-experimental-web-platform-features</code></strong> and enabling them.</p> </blockquote> <p>After setting the column count to 4, we will end up with something like this:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1024px; " > <a class="gatsby-resp-image-link" href="/static/c3660014b26c5df5cdd7fd768b727d33/2bef9/semi-aligned.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 64.81481481481481%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAAAsSAAALEgHS3X78AAADYElEQVQ4yz2TbUybVRTHn8R9009+1TnmMk3QKQJzYFyCIW4sC4oRxsDR1rBswBaMiYyNwRooOJhYMLz4xfDWSXUV0czN+IEsexGIAhmwSByuha60lL6XvtKWn/d5Fj3JyT33Puf8z81zf0eyWq24XC4CwSBenx+32624z+djc3MT2YaHh+nu7lZij8eD3+9Xvv/nTqdT0XA4HEhyUTgcJhKNEI4ID4cUoWg0SiwWU0SMo6P09/crcSAQELlR4vG44ltbW0REXSwWJ5VKIfn9QR79Y8Zus2Nbc4guTtbXnTy22Vhbs4ubbzJiMKDT6fB5vTxcXlY8LprJDeXLyM1lUbmBtORKoL0dRH/Hg+H3dUZng9z/24rZbMZsWcXu2GBo5Cqvv5LOp6fUtJz5AE1RHh0tjWg0Fezdu5us/Rmk7d5JU9NFpBmLm7KB+xwzrVBkXKFQP8fg2K8sLiwIQSvTf8zQ/oWeF55/jpLCAupVhyl/N5vztVUcKi7j6RdfZVdOPs/s2UfthSakh2YLl3X1lHZe5anGOZ4tN9FypZ/pqSnmF5e43NHO6eoz7EnbSeWJD6kozkddfIj6T6o4/rGGfQeyeOfoEd58KxPd581Iq48WGO5rYGykk5dVLUglo5w934rqoxKqa6o5eDCX9PSXyHgtg7ZmLXVnVVSpS6mrrSE3NxtJktixQ1JWtfoE0rrjMVOTd7EszzP+8zU6hya48dsEV9pb6e39CsPIIJWVGs6du8hfS2am700y/+cMi7MzDAwNoG2+hL7rS1rbdNy4+QuSjILb48Xj9YnXEphsJxQ8/IEgoVBYicfHf1KwSSYTIs+rMJva3hb7lBInEgnFZZOSyaQCpQynW0AbEaLy88tn6+JMNpPJRE9PD0khIp8FBacJUbcZCrGx4RK5boVdWUvaFkmypZ4sismwygB7xRT8L9jb9wRsMU0pAbG4kmAwouSFxDDITMp1UjwWZXLCyOy9cR7M3cK9scp314wUvH+EyprTqE9VkpmTRenRY5jq2nnQ0Mpc3zc4bt2m4qSKtwsOUFZdRGbeG2jbtEiRkJ8fDHpGf5xk7Pod7GsrfPu9kQuNDXR1d4kfricnP4+GwvewGQaxDn2NpbeDyN3rHC8vJDs3jcNlOWTu30XTpc/4F4DuJFBGsgU6AAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Half aligned with columns reducing from 5 to 4" title="Half aligned with columns reducing from 5 to 4" src="/static/c3660014b26c5df5cdd7fd768b727d33/2bef9/semi-aligned.png" srcset="/static/c3660014b26c5df5cdd7fd768b727d33/01bf6/semi-aligned.png 270w, /static/c3660014b26c5df5cdd7fd768b727d33/07484/semi-aligned.png 540w, /static/c3660014b26c5df5cdd7fd768b727d33/2bef9/semi-aligned.png 1024w" sizes="(max-width: 1024px) 100vw, 1024px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <p>So we’re one step close to have a better view, but we have the two middle columns right on the fold, and the title is spanning across too. Let’s fix the title first. We could simply set a width for it to be in the first fold, or we could give it a margin right calculating where the fold is located. Let’s use the margin solution. </p> <div class="gatsby-code-button-container" data-toaster-id="81653843877673710000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`h1 { margin-right: calc( 100vw - (env(fold-left) + env(fold-width)) ); }`, `81653843877673710000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">h1</span> <span class="token punctuation">{</span> <span class="token property">margin-right</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span> 100vw - <span class="token punctuation">(</span><span class="token function">env</span><span class="token punctuation">(</span>fold-left<span class="token punctuation">)</span> + <span class="token function">env</span><span class="token punctuation">(</span>fold-width<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div> <p>Here we’re calculating the width of the second fold and setting that as margin right for our header. Of course there are many other ways to achieve this, but I wanted to demonstrate the use of environment variables. After applying the above styles, we will end up with below, which is one step ahead to have a better UX.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1024px; " > <a class="gatsby-resp-image-link" href="/static/4dccb45080ad712cba8ff5e125560c2a/2bef9/aligned.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 64.81481481481481%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAAAsSAAALEgHS3X78AAADUElEQVQ4y32TXUxbZRjHz41Z4p03XhgSE+MuZtSEoIiL0TgzlQ02QCdrlIgTJMvciGAjmRkwE5lBdGsFErsxV1e7SqnARpxA2WAbkg7GcLqZhQxmoR+0ZW1Pv7/4+Z7DYqIX/pMned6P5/88J+/vSE6nE7/fT1iWuRcKEggE1AgGg0SjURQZjUZ0Op2aB1ZXCYVC/wqfz6fWeL1epEgkIgpjxBMJNWKxGMpePB4jIdaKzGYzXV1daq6eiX3lLB6PqyHL6x7pdBopFA6zsLjI8vIyS0tLLLtcrPj8eLw+vCs+YvEkp00/cLKnRzVkbY3/kxQKhbl56zZ37iyycNcpDN2kEmLKYIB4JKxe+tFs4mhnF4qVLywTENPIiSSBoIzbH8SzGsLlv0cwEkO6MjnNtvL3ebe2Ce3Hh2lrN3DOeoaxE21cs3zNX2Pfc6xxD2Uf1dF9dYQOu42DQ2focYzzUk0zUuFuHirei1Swi9ovTiCN2scpev4VKnfs5M2ScjSaWow9BmzH25k7a2TGqmdvZTHaAxXYf9HR2f0pFlMzjkkzz779CdKmbTy4WYP0+GtUt+iRLl2e4o3SCt6r2Enx1u3s39fIdwY9HU17uHy6gylTG9UVW/hQs5Wjh/ZRXbkLbc1bXB3o5OXqJh545BnyHisShluoadEhXbwwTn5+EYWFL1Dw5NPsKC7jsyOtVL3zOg0flKGtK+HFzZvYuPEJqspL2L39VQryn6OxvoEqTR2S9DAbNuTxaN5T7D94BMntdmPr+4mzg+cYHh5lzH4Bx8w0vYN9nB8e4vp1B82th6g/UM/NmV8Zt48wNjrK3Ow1RoYvcvKUhV7bEJbeQaamf0NSXlFhL5lMks5k/nn+yH22FA0MDGAwGNQ8GouTTKXvE7QmaqPkclmy2fVaKZvN4vF4BYculXgFVMXcI6hX/iBFVqsVvV5HJp3CJTiNRWQQJuFIFLdgdSWwiiyaZzJZpFwux39RzYgmEXF5fn5eXff393Psm241DwvW/JGUYDFFSnAq+1eQfR6y0ZDokVr/5KnJS5hOfcvnLVo6vmwnnsxy44/blJaUMjv3O322fhpav2LWk6PX4eTw4J8cn1jg1uwEEz9buHHFhufueTH5An8DRBdA6SVw+/8AAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Header aligned with using margin calculated based on fold size" title="Header aligned with using margin calculated based on fold size" src="/static/4dccb45080ad712cba8ff5e125560c2a/2bef9/aligned.png" srcset="/static/4dccb45080ad712cba8ff5e125560c2a/01bf6/aligned.png 270w, /static/4dccb45080ad712cba8ff5e125560c2a/07484/aligned.png 540w, /static/4dccb45080ad712cba8ff5e125560c2a/2bef9/aligned.png 1024w" sizes="(max-width: 1024px) 100vw, 1024px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <p>Now is the time to fix the two middle columns. One way to fix the middle column problem is to add an empty column which has no content. But it’s easier said than done. If you’re willing to play with the width of the columns, you can get away with something like this:</p> <div class="gatsby-code-button-container" data-toaster-id="86009961585174400000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`@media (screen-spanning: single-fold-vertical) { .grid { grid-template-columns: repeat(4, 23%); grid-gap: 25px; } .card:nth-child(4n + 2) { margin-right: 5px; } .card:nth-child(4n + 3) { margin-left: 10px; } }`, `86009961585174400000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">screen-spanning</span><span class="token punctuation">:</span> single-fold-vertical<span class="token punctuation">)</span></span> <span class="token punctuation">{</span> <span class="token selector">.grid</span> <span class="token punctuation">{</span> <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> <span class="token function">repeat</span><span class="token punctuation">(</span>4<span class="token punctuation">,</span> 23%<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">grid-gap</span><span class="token punctuation">:</span> 25px<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.card:nth-child(4n + 2)</span> <span class="token punctuation">{</span> <span class="token property">margin-right</span><span class="token punctuation">:</span> 5px<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.card:nth-child(4n + 3)</span> <span class="token punctuation">{</span> <span class="token property">margin-left</span><span class="token punctuation">:</span> 10px<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div> <p>This will result in:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1024px; " > <a class="gatsby-resp-image-link" href="/static/3a6fefcc61860b93d168b01cf2a90650/2bef9/half-aligned.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 64.81481481481481%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAAAsSAAALEgHS3X78AAADFElEQVQ4y42TX2xTVRzH74uJD75hDI8almiijxDCkpHwwIjBuL2ZSAjggzGazET+6GbIEHTM4Qilu8t0LKGMbdJB7cZQgsQliwMnbKujXZ2CHVuxXXtvb29vb2/brf14zh2Q+MYv+eZ8zzm/f+ec71GWlpZIp9OYuRwZw0DTNBeG4JZlIc3n8+HxeFyu6TrZbPZ/SKVSbkwymUTJ5/MUbJuC4+AI2IJbcq1QcOfShoaGUFXV5bKI46zvSR/pnxPNyDzlchnFsvIsLcdJJFeeQnania5l58ViEb/fT19fH89iim1bxJdjJP59KJI9EkmSOKVV8sWyGMuuUyAY5MyZTsEqoljKRS5nsBiLEQ5Hic4vEJ6LkDWyKE4+xT/3xpj7dQBjcRxKDxgdn6TNN0zg1jRhzeR0Xz+tRz9mefkOodANpqZ+4O6dm+yq28nzz23kpQ017HijBv/AMMqD6Cw9nS1cPt/BxOVTPPx9mM7eQXa//xkt6kXO/TxL0wkPqrcdqhqJR3PEF28Tjdzmo3caeP2V16jbVsun+xu5dOF7lOj0JOpXh1A7PsfbfpjxawOo/Z3Uv1fL3uZGDrS/y449Ozl1spl0YoqZ3y4x6m/j+lg/LR/up3FXPa1Hmtj3Vj2D5wdR/ozM0n26lbbWIxxvbuKq38fX6kG27H6BhgOv0vDBJra++TJfHvuEZPwWf9wd5ea1bn654Wfb1no2vFjD9i11vF27Gf+gOLKdt8Tl3mclEcfQxYXrmvs4ofA0C3/PY5ga3537Fu9ZD2trZXHxunh5W8jGZmY6xMTEJCExLoTvoWs6SrVaxciaQtgWppmjvLpKpVIVgSaZTNZ95ZGRUbqEDtfEekKIN5dbF/yq8LULtqvJkuCubOSinsm4v0SKVopTQorVyK4nDAQCeL1el5um6e5XKpXHvyQt4g0hckecYA3liSBlp09MOkuUH1eVCXt7n1HYsdhfRCIhVnSDkR/H8PZ4cYolcYySW1VaMHiVwwf3Ebyi0nX2GD3dX3D9pyscP9HGoaMdnOy6QMs3vczM3+c/z5dsLFH9dV0AAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Columns aligned on the two sides of the fold" title="Columns aligned on the two sides of the fold" src="/static/3a6fefcc61860b93d168b01cf2a90650/2bef9/half-aligned.png" srcset="/static/3a6fefcc61860b93d168b01cf2a90650/01bf6/half-aligned.png 270w, /static/3a6fefcc61860b93d168b01cf2a90650/07484/half-aligned.png 540w, /static/3a6fefcc61860b93d168b01cf2a90650/2bef9/half-aligned.png 1024w" sizes="(max-width: 1024px) 100vw, 1024px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <p>You can see we’ve come a long way from having a completely spanned content to a neat ordered view. But that’s all have been using only the CSS media feature. Let’s see what does the Window Segment Enumeration API have to offer.</p> <h2 id="window-segments-enumeration-api" style="position:relative;"><a href="#window-segments-enumeration-api" aria-label="window segments enumeration api permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Window Segments Enumeration API</h2> <p>This API helps you to deal with non-DOM elements such as a canvas or WebGL objects. You can leverage the <code class="language-text">getWindowSegments()</code> function which is accessible on the window object and returns an array of one or more <em>DOMRect</em> representing the geometry of and position of each display region:</p> <div class="gatsby-code-button-container" data-toaster-id="22750605376436540000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const segments = window.getWindowSegments(); // case 1: desktops, traditional touch screen devices, foldable device not spanned console.log(segments.length) // 1 // case 2: dual-screen and foldable console.log(segments.length) // 2`, `22750605376436540000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> segments <span class="token operator">=</span> window<span class="token punctuation">.</span><span class="token function">getWindowSegments</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// case 1: desktops, traditional touch screen devices, foldable device not spanned</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>segments<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token comment">// 1</span> <span class="token comment">// case 2: dual-screen and foldable </span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>segments<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token comment">// 2</span></code></pre></div> <p>If you wanted to know the fold posture inside your JavaScript code, you can calculate them easily using below snippet:</p> <div class="gatsby-code-button-container" data-toaster-id="94463304877329760000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`function isSingleFoldHorizontal() { const segments = window.getWindowSegments(); if( segments.length !== 2 ) { return false; } if( segments[0].top < segments[1].top ) { return true; } return false; }`, `94463304877329760000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">isSingleFoldHorizontal</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> segments <span class="token operator">=</span> window<span class="token punctuation">.</span><span class="token function">getWindowSegments</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span> segments<span class="token punctuation">.</span>length <span class="token operator">!==</span> <span class="token number">2</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span><span class="token punctuation">(</span> segments<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>top <span class="token operator">&lt;</span> segments<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span>top <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div> <p>Here we’re simply retuning false if the segments are now two, then check whether the top value of segment 0 is less than segment 1 which means the device is in horizontal state. If not we’re returning false which means it’s vertical posture.</p> <h2 id="where-to-start" style="position:relative;"><a href="#where-to-start" aria-label="where to start permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Where to start?</h2> <p>You can access the CSS screen-spanning media features using the <a href="edge://flags/#enable-experimental-web-platform-features">experimental web platform feature flag</a>, and the JavaScript Window Segments Enumeration API is accessible by enabling the <a href="edge://flags/#enable-javascript-harmony">Experimental JavaScript flag</a>. </p> <p>You also have the option of using Origin Trials, where you can acquire tokens and safely experiment with these new primitives in production in exchange for providing feedback about the APIs. <a href="https://developer.microsoft.com/en-us/microsoft-edge/origin-trials/dual-screen-and-foldable-devices-css-and/detail/">Sign up for an Origin Trial if you’re interested in testing out these APIs!</a> </p> <p><a href="https://glitch.com/edit/#!/pwa-dual-screen">PS: You can find all the the code on Glitch here.</a></p><![CDATA[How to use Azure Cosmos Emulator as a local MongoDb database 🌍]]>https://yashints.dev/blog/2020/11/30/az-cosmos-emulatorhttps://yashints.dev/blog/2020/11/30/az-cosmos-emulatorMon, 30 Nov 2020 00:00:00 GMT<p>I recently was trying to prepare a demo which involved me having a local MongoDb database. I reviewed a few options and was about to choose one when I remembered I have <a href="https://yas.fyi/azcosemu">Azure Cosmos DB Emulator</a> installed and Cosmos DB supports MongoDb APIs.</p> <!--more--> <h2 id="install-if-you-havent-already" style="position:relative;"><a href="#install-if-you-havent-already" aria-label="install if you havent already permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Install if you haven’t already</h2> <p>You will need below requirements to be able to install the emulator:</p> <ul> <li>Windows Server 2012 R2, Windows Server 2016, 2019 or Windows 8 and 10. Docker on Windows, Linux and macOS is also supported.</li> <li>64-bit OS.</li> <li>Minimum 2GB RAM.</li> <li>At least 10GB available hard disk space.</li> </ul> <p>If you’ve ticked all of above already, then head <a href="https://aka.ms/cosmosdb-emulator">over here and install the latest version</a>. If you stumbled upon any issues use <a href="https://docs.microsoft.com/en-us/azure/cosmos-db/troubleshoot-local-emulator">the troubleshooting guide</a> to find out what’s happening.</p> <blockquote> <p>💡 Make sure you check for updates regularly since each new version might contain new features and bug fixes.</p> </blockquote> <h2 id="starting-the-emulator" style="position:relative;"><a href="#starting-the-emulator" aria-label="starting the emulator permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Starting the emulator</h2> <p>Normally you would use the Windows start menu to find your programs and start the application, however, for the emulator to support MongoDB APIs, you will need to pass the <code class="language-text">EnableMongoDbEndpoint</code> argument. </p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1080px; " > <a class="gatsby-resp-image-link" href="/static/4de7592b693bf405cbfca0e60aeb55dc/d8309/startingthecosmosdbemulator.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 81.85185185185185%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAQABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAMEBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHQY5iTlIv/xAAZEAACAwEAAAAAAAAAAAAAAAAAAwEQFBP/2gAIAQEAAQUC4LM6jOki/wD/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAaEAACAgMAAAAAAAAAAAAAAAAAAjORASAy/9oACAEBAAY/AuMURrRGun//xAAZEAACAwEAAAAAAAAAAAAAAAAAARARIfH/2gAIAQEAAT8hRrHLRyhBR//aAAwDAQACAAMAAAAQXM//xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAwEBPxAJ/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAGxABAAICAwAAAAAAAAAAAAAAAQARQVEhkeH/2gAIAQEAAT8Q8HlwNgomzpzIjcAc5qWT/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Starting Azure Cosmos DB Emulator" title="Starting Azure Cosmos DB Emulator" src="/static/4de7592b693bf405cbfca0e60aeb55dc/47311/startingthecosmosdbemulator.jpg" srcset="/static/4de7592b693bf405cbfca0e60aeb55dc/6f81f/startingthecosmosdbemulator.jpg 270w, /static/4de7592b693bf405cbfca0e60aeb55dc/09d21/startingthecosmosdbemulator.jpg 540w, /static/4de7592b693bf405cbfca0e60aeb55dc/47311/startingthecosmosdbemulator.jpg 1080w, /static/4de7592b693bf405cbfca0e60aeb55dc/d8309/startingthecosmosdbemulator.jpg 1165w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <p>You have a few options here:</p> <ol> <li>Create a shortcut and pass the required arguments</li> <li>Use command line to start it</li> </ol> <p>I am going to use <a href="https://github.com/microsoft/terminal">Windows Terminal</a>. Run the below command to fire up the emulator with MongoDB support:</p> <div class="gatsby-code-button-container" data-toaster-id="78129217816518050000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`& 'C:\Program Files\Azure Cosmos DB Emulator\CosmosDB.Emulator.exe' /EnableMongoDbEndpoint`, `78129217816518050000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token operator">&amp;</span> <span class="token string">'C:\Program Files\Azure Cosmos DB Emulator\CosmosDB.Emulator.exe'</span> /EnableMongoDbEndpoint</code></pre></div> <p>You will be prompted to approve the emulator making changes to your system and once approved, you will see the emulator starting and the interface will open in your default browser.</p> <h2 id="getting-the-connection-string" style="position:relative;"><a href="#getting-the-connection-string" aria-label="getting the connection string permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Getting the connection string</h2> <p>The very first thing you’d see is the quick start which should look something like this:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1080px; " > <a class="gatsby-resp-image-link" href="/static/1ded639cfb17580528aea8c832a21acb/57b36/emulatorquickstart.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 50%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAwABBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAei+uDNH/8QAGhAAAgMBAQAAAAAAAAAAAAAAAgMAARMQM//aAAgBAQABBQJQVasxmYRPjz//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAcEAABAwUAAAAAAAAAAAAAAAACADKRECIxUXH/2gAIAQEABj8CG0caTBhMGEHK/wD/xAAdEAABAgcAAAAAAAAAAAAAAAAAARARITFBobHx/9oACAEBAAE/IVRiy1KXh8gY/T//2gAMAwEAAgADAAAAEOAP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAGxABAAICAwAAAAAAAAAAAAAAAQAREPBRocH/2gAIAQEAAT8QDLlVJbolTqiaN5NHwz//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Azure Cosmos DB Emulator connection string page" title="Azure Cosmos DB Emulator connection string page" src="/static/1ded639cfb17580528aea8c832a21acb/47311/emulatorquickstart.jpg" srcset="/static/1ded639cfb17580528aea8c832a21acb/6f81f/emulatorquickstart.jpg 270w, /static/1ded639cfb17580528aea8c832a21acb/09d21/emulatorquickstart.jpg 540w, /static/1ded639cfb17580528aea8c832a21acb/47311/emulatorquickstart.jpg 1080w, /static/1ded639cfb17580528aea8c832a21acb/0047d/emulatorquickstart.jpg 1620w, /static/1ded639cfb17580528aea8c832a21acb/274e1/emulatorquickstart.jpg 2160w, /static/1ded639cfb17580528aea8c832a21acb/57b36/emulatorquickstart.jpg 2425w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <p>What you’ll need is the <em>Mongo Connection String</em>. Copy that you’ll be ready to kick start. I am going to use the Node sample from the quick start to continue the rest of this guide, but you can use this straight away in your current code.</p> <h2 id="creating-a-nodejs-web-api-project" style="position:relative;"><a href="#creating-a-nodejs-web-api-project" aria-label="creating a nodejs web api project permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Creating a Node.js Web API project</h2> <p>Open up a command prompt in a new folder and initiate a project:</p> <div class="gatsby-code-button-container" data-toaster-id="9846285064508086000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`npm init -y`, `9846285064508086000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> init -y</code></pre></div> <p>The next thing to do is to install the dependencies:</p> <div class="gatsby-code-button-container" data-toaster-id="40685595138105720000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`# linux or macOS touch app.js # Windows echo &quot;&quot; > app.js # install dependencies npm install express mongodb body-parser`, `40685595138105720000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token comment"># linux or macOS</span> <span class="token function">touch</span> app.js <span class="token comment"># Windows</span> <span class="token builtin class-name">echo</span> <span class="token string">""</span> <span class="token operator">></span> app.js <span class="token comment"># install dependencies</span> <span class="token function">npm</span> <span class="token function">install</span> express mongodb body-parser</code></pre></div> <h3 id="the-app" style="position:relative;"><a href="#the-app" aria-label="the app permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>The app</h3> <p>We would have a simple application, since this tutorial is not a Node.js or Express.js focused, I will just brush on some steps here. Feel free to go through and understand each of these at your own pace.</p> <div class="gatsby-code-button-container" data-toaster-id="99816711848638760000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const Express = require(&quot;express&quot;); const BodyParser = require(&quot;body-parser&quot;); const MongoClient = require(&quot;mongodb&quot;).MongoClient; const ObjectId = require(&quot;mongodb&quot;).ObjectID; var app = Express(); app.use(BodyParser.json()); app.use(BodyParser.urlencoded({ extended: true })); app.listen(5000, () => {});`, `99816711848638760000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> Express <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"express"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> BodyParser <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"body-parser"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> MongoClient <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"mongodb"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>MongoClient<span class="token punctuation">;</span> <span class="token keyword">const</span> ObjectId <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"mongodb"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>ObjectID<span class="token punctuation">;</span> <span class="token keyword">var</span> app <span class="token operator">=</span> <span class="token function">Express</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> app<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>BodyParser<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> app<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>BodyParser<span class="token punctuation">.</span><span class="token function">urlencoded</span><span class="token punctuation">(</span><span class="token punctuation">{</span> extended<span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> app<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span><span class="token number">5000</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div> <p>What we have here is a simple web server which responds to <code class="language-text">http://localhost:5000</code>. All we’re doing is initializing the <code class="language-text">MongoClient</code> and a web server. Next thing we need to do is to establish a connection with MongoDB interface of our emulator:</p> <div class="gatsby-code-button-container" data-toaster-id="76850686005073610000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const Express = require(&quot;express&quot;); const BodyParser = require(&quot;body-parser&quot;); const MongoClient = require(&quot;mongodb&quot;).MongoClient; const ObjectId = require(&quot;mongodb&quot;).ObjectID; const CONNECTION_URL = &quot;YOUR CONNECTION STRING&quot;; const DATABASE_NAME = &quot;cosmos_emulator_mongo&quot;; var app = Express(); app.use(BodyParser.json()); app.use(BodyParser.urlencoded({ extended: true })); var database, collection; app.listen(5000, () => { MongoClient.connect(CONNECTION_URL, { useNewUrlParser: true }, (error, client) => { if(error) { throw error; } database = client.db(DATABASE_NAME); collection = database.collection(&quot;celebrities&quot;); console.log(&quot;Connected to \`&quot; + DATABASE_NAME + &quot;\`!&quot;); }); });`, `76850686005073610000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> Express <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"express"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> BodyParser <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"body-parser"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> MongoClient <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"mongodb"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>MongoClient<span class="token punctuation">;</span> <span class="token keyword">const</span> ObjectId <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"mongodb"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>ObjectID<span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token constant">CONNECTION_URL</span> <span class="token operator">=</span> <span class="token string">"YOUR CONNECTION STRING"</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token constant">DATABASE_NAME</span> <span class="token operator">=</span> <span class="token string">"cosmos_emulator_mongo"</span><span class="token punctuation">;</span> <span class="token keyword">var</span> app <span class="token operator">=</span> <span class="token function">Express</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> app<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>BodyParser<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> app<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>BodyParser<span class="token punctuation">.</span><span class="token function">urlencoded</span><span class="token punctuation">(</span><span class="token punctuation">{</span> extended<span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> database<span class="token punctuation">,</span> collection<span class="token punctuation">;</span> app<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span><span class="token number">5000</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> MongoClient<span class="token punctuation">.</span><span class="token function">connect</span><span class="token punctuation">(</span><span class="token constant">CONNECTION_URL</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> useNewUrlParser<span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">error<span class="token punctuation">,</span> client</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span><span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> error<span class="token punctuation">;</span> <span class="token punctuation">}</span> database <span class="token operator">=</span> client<span class="token punctuation">.</span><span class="token function">db</span><span class="token punctuation">(</span><span class="token constant">DATABASE_NAME</span><span class="token punctuation">)</span><span class="token punctuation">;</span> collection <span class="token operator">=</span> database<span class="token punctuation">.</span><span class="token function">collection</span><span class="token punctuation">(</span><span class="token string">"celebrities"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Connected to `"</span> <span class="token operator">+</span> <span class="token constant">DATABASE_NAME</span> <span class="token operator">+</span> <span class="token string">"`!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div> <p>The next thing we do to make it simpler to run the app is to add a start script to our <code class="language-text">package.json</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="72315294001403216000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`&quot;scripts&quot;: { &quot;start&quot;: &quot;node app.js&quot; }`, `72315294001403216000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"start"</span><span class="token operator">:</span> <span class="token string">"node app.js"</span> <span class="token punctuation">}</span></code></pre></div> <p>If you run <code class="language-text">npm start</code> now, you should see the message connected to <code class="language-text">Connected to &#39;cosmos_emulator_mongo&#39;</code> printed on your console which means you’ve successfully connected to the MongoDb APIs.</p> <h3 id="seed-the-database" style="position:relative;"><a href="#seed-the-database" aria-label="seed the database permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Seed the database</h3> <p>First let’s create a JSON file which contains some celebrities 😎:</p> <div class="gatsby-code-button-container" data-toaster-id="73152402074366460000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`[{ &quot;age&quot;: 18, &quot;birth_place&quot;: &quot;Harij, Gujarat, India&quot;, &quot;birth_sign&quot;: &quot;Pisces&quot;, &quot;birth_year&quot;: &quot;1996&quot;, &quot;birthday&quot;: &quot;September 28&quot;, &quot;name&quot;: &quot;Daxeel Soni&quot;, &quot;occupation&quot;: &quot;Developer of this API. More: www.daxeelsoni.in&quot;, &quot;photo_url&quot;: &quot;http://daxeelsoni.in/images/me.jpg&quot; }, { &quot;age&quot;: 28, &quot;birth_place&quot;: &quot;Houston&quot;, &quot;birth_sign&quot;: &quot;Libra&quot;, &quot;birth_year&quot;: &quot;1987&quot;, &quot;birthday&quot;: &quot;September 28&quot;, &quot;name&quot;: &quot;Hilary Duff&quot;, &quot;occupation&quot;: &quot;TV Actress&quot;, &quot;photo_url&quot;: &quot;http://www.famousbirthdays.com/thumbnails/duff-hilary-medium.jpg&quot; }, { &quot;age&quot;: 38, &quot;birth_place&quot;: &quot;Columbia&quot;, &quot;birth_sign&quot;: &quot;Libra&quot;, &quot;birth_year&quot;: &quot;1977&quot;, &quot;birthday&quot;: &quot;September 28&quot;, &quot;name&quot;: &quot;Young Jeezy&quot;, &quot;occupation&quot;: &quot;Rapper&quot;, &quot;photo_url&quot;: &quot;http://www.famousbirthdays.com/thumbnails/jeezy-young-medium.jpg&quot; }, { &quot;age&quot;: 48, &quot;birth_place&quot;: &quot;Roanoke&quot;, &quot;birth_sign&quot;: &quot;Libra&quot;, &quot;birth_year&quot;: &quot;1967&quot;, &quot;birthday&quot;: &quot;September 28&quot;, &quot;name&quot;: &quot;Challen Cates&quot;, &quot;occupation&quot;: &quot;TV Actress&quot;, &quot;photo_url&quot;: &quot;http://www.famousbirthdays.com/thumbnails/cates-challen-medium.jpg&quot; }]`, `73152402074366460000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token property">"age"</span><span class="token operator">:</span> <span class="token number">18</span><span class="token punctuation">,</span> <span class="token property">"birth_place"</span><span class="token operator">:</span> <span class="token string">"Harij, Gujarat, India"</span><span class="token punctuation">,</span> <span class="token property">"birth_sign"</span><span class="token operator">:</span> <span class="token string">"Pisces"</span><span class="token punctuation">,</span> <span class="token property">"birth_year"</span><span class="token operator">:</span> <span class="token string">"1996"</span><span class="token punctuation">,</span> <span class="token property">"birthday"</span><span class="token operator">:</span> <span class="token string">"September 28"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"Daxeel Soni"</span><span class="token punctuation">,</span> <span class="token property">"occupation"</span><span class="token operator">:</span> <span class="token string">"Developer of this API. More: www.daxeelsoni.in"</span><span class="token punctuation">,</span> <span class="token property">"photo_url"</span><span class="token operator">:</span> <span class="token string">"http://daxeelsoni.in/images/me.jpg"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">"age"</span><span class="token operator">:</span> <span class="token number">28</span><span class="token punctuation">,</span> <span class="token property">"birth_place"</span><span class="token operator">:</span> <span class="token string">"Houston"</span><span class="token punctuation">,</span> <span class="token property">"birth_sign"</span><span class="token operator">:</span> <span class="token string">"Libra"</span><span class="token punctuation">,</span> <span class="token property">"birth_year"</span><span class="token operator">:</span> <span class="token string">"1987"</span><span class="token punctuation">,</span> <span class="token property">"birthday"</span><span class="token operator">:</span> <span class="token string">"September 28"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"Hilary Duff"</span><span class="token punctuation">,</span> <span class="token property">"occupation"</span><span class="token operator">:</span> <span class="token string">"TV Actress"</span><span class="token punctuation">,</span> <span class="token property">"photo_url"</span><span class="token operator">:</span> <span class="token string">"http://www.famousbirthdays.com/thumbnails/duff-hilary-medium.jpg"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">"age"</span><span class="token operator">:</span> <span class="token number">38</span><span class="token punctuation">,</span> <span class="token property">"birth_place"</span><span class="token operator">:</span> <span class="token string">"Columbia"</span><span class="token punctuation">,</span> <span class="token property">"birth_sign"</span><span class="token operator">:</span> <span class="token string">"Libra"</span><span class="token punctuation">,</span> <span class="token property">"birth_year"</span><span class="token operator">:</span> <span class="token string">"1977"</span><span class="token punctuation">,</span> <span class="token property">"birthday"</span><span class="token operator">:</span> <span class="token string">"September 28"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"Young Jeezy"</span><span class="token punctuation">,</span> <span class="token property">"occupation"</span><span class="token operator">:</span> <span class="token string">"Rapper"</span><span class="token punctuation">,</span> <span class="token property">"photo_url"</span><span class="token operator">:</span> <span class="token string">"http://www.famousbirthdays.com/thumbnails/jeezy-young-medium.jpg"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">"age"</span><span class="token operator">:</span> <span class="token number">48</span><span class="token punctuation">,</span> <span class="token property">"birth_place"</span><span class="token operator">:</span> <span class="token string">"Roanoke"</span><span class="token punctuation">,</span> <span class="token property">"birth_sign"</span><span class="token operator">:</span> <span class="token string">"Libra"</span><span class="token punctuation">,</span> <span class="token property">"birth_year"</span><span class="token operator">:</span> <span class="token string">"1967"</span><span class="token punctuation">,</span> <span class="token property">"birthday"</span><span class="token operator">:</span> <span class="token string">"September 28"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"Challen Cates"</span><span class="token punctuation">,</span> <span class="token property">"occupation"</span><span class="token operator">:</span> <span class="token string">"TV Actress"</span><span class="token punctuation">,</span> <span class="token property">"photo_url"</span><span class="token operator">:</span> <span class="token string">"http://www.famousbirthdays.com/thumbnails/cates-challen-medium.jpg"</span> <span class="token punctuation">}</span><span class="token punctuation">]</span></code></pre></div> <p>Now that we have our JSON file, let’s seed the database. Replace the initial connect code with this:</p> <div class="gatsby-code-button-container" data-toaster-id="81212631444754810000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`app.listen(5000, () => { MongoClient.connect( CONNECTION_URL, { useNewUrlParser: true, sslValidate: false, }, (error, client) => { if (error) { throw error; } database = client.db(DATABASE_NAME); collection = database.collection(&quot;celebrities&quot;); collection.estimatedDocumentCount({}, (erorr, numOfRecords) => { if (numOfRecords <= 0) { fs.readFile(&quot;./info.json&quot;, &quot;utf8&quot;, (err, data) => { if (err) { console.log(\`Error reading file from disk: \${err}\`); } else { // parse JSON string to JSON object const celebrities = JSON.parse(data); collection.insertMany(celebrities, (error, result) => { if (error) { console.log(\`Error in saving seed data: \${error}\`); } console.log(\`Seed data inserted into the database!\`); }); } }); } else { console.log(\`Connected to database\`); } }); } ); });`, `81212631444754810000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript">app<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span><span class="token number">5000</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> MongoClient<span class="token punctuation">.</span><span class="token function">connect</span><span class="token punctuation">(</span> <span class="token constant">CONNECTION_URL</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> useNewUrlParser<span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> sslValidate<span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">error<span class="token punctuation">,</span> client</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> error<span class="token punctuation">;</span> <span class="token punctuation">}</span> database <span class="token operator">=</span> client<span class="token punctuation">.</span><span class="token function">db</span><span class="token punctuation">(</span><span class="token constant">DATABASE_NAME</span><span class="token punctuation">)</span><span class="token punctuation">;</span> collection <span class="token operator">=</span> database<span class="token punctuation">.</span><span class="token function">collection</span><span class="token punctuation">(</span><span class="token string">"celebrities"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> collection<span class="token punctuation">.</span><span class="token function">estimatedDocumentCount</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">erorr<span class="token punctuation">,</span> numOfRecords</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>numOfRecords <span class="token operator">&lt;=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> fs<span class="token punctuation">.</span><span class="token function">readFile</span><span class="token punctuation">(</span><span class="token string">"./info.json"</span><span class="token punctuation">,</span> <span class="token string">"utf8"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">err<span class="token punctuation">,</span> data</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Error reading file from disk: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>err<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token comment">// parse JSON string to JSON object</span> <span class="token keyword">const</span> celebrities <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span> collection<span class="token punctuation">.</span><span class="token function">insertMany</span><span class="token punctuation">(</span>celebrities<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">error<span class="token punctuation">,</span> result</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Error in saving seed data: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>error<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Seed data inserted into the database!</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Connected to database</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div> <p>All we’re doing here is to get the number of records in the collection and if there is nothing, read the JSON file and write it to the collection.</p> <p>Don’t forget to add <code class="language-text">const fs = require(&#39;fs&#39;)</code> at the top with other require statements.</p> <p>Now if you run <code class="language-text">npm start</code> would should see the application start and then the <strong>seed data inserted</strong> message.</p> <h3 id="creating-the-endpoint" style="position:relative;"><a href="#creating-the-endpoint" aria-label="creating the endpoint permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Creating the endpoint</h3> <p>And now all we need is to add our get endpoint to be able to fetch our celebrities. Don’t forget to add it before you create your listener:</p> <div class="gatsby-code-button-container" data-toaster-id="24084494550032966000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`app.get(&quot;/api/celebrities&quot;, (request, response) => { collection.find({}).toArray((error, result) => { if(error) { return response.status(500).send(error); } response.send(result); }); });`, `24084494550032966000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript">app<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">"/api/celebrities"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">request<span class="token punctuation">,</span> response</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> collection<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toArray</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">error<span class="token punctuation">,</span> result</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span><span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> response<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>error<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> response<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div> <h2 id="testing-the-application" style="position:relative;"><a href="#testing-the-application" aria-label="testing the application permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Testing the application</h2> <p>You’re now ready to get your celebrities via the API. Simply open a browser and head over to <code class="language-text">http://localhost:5000/api/celebrities</code> or just use the below command:</p> <div class="gatsby-code-button-container" data-toaster-id="89308119075790360000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`curl -X GET http://localhost:5000/api/celebrities`, `89308119075790360000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">curl</span> -X GET http://localhost:5000/api/celebrities</code></pre></div> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>In this guide we saw how to use Azure Cosmos DB Emulator with MongoDb API to have a local MongoDb available for our local development and proof of concepts. Hope this has helped you save some time and also the trouble of installing yet another software on your system (of course if you already are using the emulator 😊).</p> <p>Enjoy hacking and let us know what awesome projects you’re doing using the emulator.</p> <p>PS: You can find the finished code in my <a href="https://github.com/yashints/azure-cosmosdb-emulator-mongodb">GitHub repository here</a>.</p><![CDATA[Access your clipboard on your other devices 😍 📋]]>https://yashints.dev/blog/2020/11/13/copy-across-deviceshttps://yashints.dev/blog/2020/11/13/copy-across-devicesFri, 13 Nov 2020 00:00:00 GMT<p>How many times have you been working on multiple systems and realised you are trying to paste something which you have copied on the other system? Well with the help of this article you can now share your clipboard between your <strong>Windows</strong> and <strong>Mac</strong> devices 😎.</p> <!--more--> <h2 id="windows-to-windows" style="position:relative;"><a href="#windows-to-windows" aria-label="windows to windows permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Windows to Windows</h2> <p>If you have multiple windows devices, it’s very easy. Simply open your control panel and search for <em>Clipboard Settings</em>.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1080px; " > <a class="gatsby-resp-image-link" href="/static/b63796ebac291e25c796b69897fe398b/7f09e/windows-clipboard.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 71.48148148148148%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAOABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAMBAgX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAB2HUYgSL/AP/EABcQAQADAAAAAAAAAAAAAAAAAAEAIEH/2gAIAQEAAQUCCZT/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAUEAEAAAAAAAAAAAAAAAAAAAAg/9oACAEBAAY/Al//xAAbEAABBAMAAAAAAAAAAAAAAAABABARITFBkf/aAAgBAQABPyHRfVFGAhDDf//aAAwDAQACAAMAAAAQDw//xAAWEQADAAAAAAAAAAAAAAAAAAABEBH/2gAIAQMBAT8QgX//xAAVEQEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAgEBPxCn/8QAHBABAAEEAwAAAAAAAAAAAAAAAQAQESExQXGR/9oACAEBAAE/ECvl7wSAprNB4F5o6p//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Opening clipboard settings on windows" title="Opening clipboard settings on windows" src="/static/b63796ebac291e25c796b69897fe398b/47311/windows-clipboard.jpg" srcset="/static/b63796ebac291e25c796b69897fe398b/6f81f/windows-clipboard.jpg 270w, /static/b63796ebac291e25c796b69897fe398b/09d21/windows-clipboard.jpg 540w, /static/b63796ebac291e25c796b69897fe398b/47311/windows-clipboard.jpg 1080w, /static/b63796ebac291e25c796b69897fe398b/7f09e/windows-clipboard.jpg 1156w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <p>Once opened, set the <strong>Sync across devices</strong> option to on. If you want to prevent sensitive data to be synced and do it on a case by case basis, set the <strong>Never automatically sync text that I copy</strong> option to on instead.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1080px; " > <a class="gatsby-resp-image-link" href="/static/1c3782258e317f014eda43682c3642ad/9e699/clipboard-settings-windows.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 77.77777777777777%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAQABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAQBBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAenZHYGj/8QAFhAAAwAAAAAAAAAAAAAAAAAAAxAx/9oACAEBAAEFAhVCq//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAACD/2gAIAQEABj8CX//EABkQAAMAAwAAAAAAAAAAAAAAAAABECExcf/aAAgBAQABPyFshTdwU//aAAwDAQACAAMAAAAQAw//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAcEAABBAMBAAAAAAAAAAAAAAABABARMSFBYbH/2gAIAQEAAT8Q5OAilqZmnqptv//Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Clipboard settings on windows" title="Clipboard settings on windows" src="/static/1c3782258e317f014eda43682c3642ad/47311/clipboard-settings-windows.jpg" srcset="/static/1c3782258e317f014eda43682c3642ad/6f81f/clipboard-settings-windows.jpg 270w, /static/1c3782258e317f014eda43682c3642ad/09d21/clipboard-settings-windows.jpg 540w, /static/1c3782258e317f014eda43682c3642ad/47311/clipboard-settings-windows.jpg 1080w, /static/1c3782258e317f014eda43682c3642ad/0047d/clipboard-settings-windows.jpg 1620w, /static/1c3782258e317f014eda43682c3642ad/9e699/clipboard-settings-windows.jpg 1795w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <p>While you’re at it, turn clipboard history on too to have a beautiful clipboard history available by pressing <kbd>Win</kbd>+<kbd>V</kbd>.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 433px; " > <a class="gatsby-resp-image-link" href="/static/674b46e8eac0424a0c58915840d6d2dd/3561e/clipboard-history.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 132.96296296296296%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAbABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAMBAgX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAB9fetSSgVjVZg/8QAGhAAAgMBAQAAAAAAAAAAAAAAAAECEBESIf/aAAgBAQABBQLDkfgsa5GQqVyP/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPwEf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPwEf/8QAFRABAQAAAAAAAAAAAAAAAAAAIAH/2gAIAQEABj8CVX//xAAeEAACAgICAwAAAAAAAAAAAAAAAREhMVEQQWGBwf/aAAgBAQABPyFTv7wWUJidiiHkzwatl7Mjr0JKFQln/9oADAMBAAIAAwAAABB/Mjz/xAAXEQADAQAAAAAAAAAAAAAAAAAAAREQ/9oACAEDAQE/EIR7/8QAFhEAAwAAAAAAAAAAAAAAAAAAABAR/9oACAECAQE/ECv/xAAbEAEBAQADAQEAAAAAAAAAAAABEQAhQVExkf/aAAgBAQABPxBxFaYJQWHbTHzglxKU8Ge4BGKYkyePNyPh27vBp4fmDNevMMM8ZjI+eYAwPm//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Windows clipboard history" title="Windows clipboard history" src="/static/674b46e8eac0424a0c58915840d6d2dd/3561e/clipboard-history.jpg" srcset="/static/674b46e8eac0424a0c58915840d6d2dd/6f81f/clipboard-history.jpg 270w, /static/674b46e8eac0424a0c58915840d6d2dd/3561e/clipboard-history.jpg 433w" sizes="(max-width: 433px) 100vw, 433px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <h3 id="use-the-copied-text" style="position:relative;"><a href="#use-the-copied-text" aria-label="use the copied text permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Use the copied text</h3> <p>Now if you copy something into your clipboard, based on assuming you wanted to sync everything, simply paste, or open your clipboard history on the target device to see it.</p> <blockquote> <p>⚠️ If you selected never automatically sync option, you can press <kbd>Win</kbd>+<kbd>V</kbd> to open up your clipboard history and select what you want to be synced across your devices after copying the items.</p> </blockquote> <h3 id="additional-tip" style="position:relative;"><a href="#additional-tip" aria-label="additional tip permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Additional tip</h3> <p>If you choose to use clipboard history, make sure you pin items you use frequently to save yourself some more time too.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 429px; " > <a class="gatsby-resp-image-link" href="/static/5943b22bbb49e2802deb3e2cfd714760/09fc4/pin-history.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 134.8148148148148%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAbABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAIBAwUE/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAdfi0oSkcLGV1QA//8QAGxAAAwACAwAAAAAAAAAAAAAAAAECAzEQESH/2gAIAQEAAQUC6RN5Kp+C00NC0Mnhn//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQMBAT8BH//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BH//EABkQAQACAwAAAAAAAAAAAAAAAAEAAhEwMf/aAAgBAQAGPwLssBXBr//EABwQAAIDAQADAAAAAAAAAAAAAAABESExUUFhof/aAAgBAQABPyFVt/ZY5MNzfDCdixE0o5I9BKGF+Wa0RQQjZ//aAAwDAQACAAMAAAAQzyoA/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAEREP/aAAgBAwEBPxCEe//EABYRAAMAAAAAAAAAAAAAAAAAAAAQEf/aAAgBAgEBPxAr/8QAHBABAAMBAAMBAAAAAAAAAAAAAQARMSFBYZFx/9oACAEBAAE/EGFAunhAtKrrIUt+1sHF9BBlzsBaLpiKK/YlnWeZiNKNYccB9TL0lBwyeg+QFOGT/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Pin items in clipboard history on windows" title="Pin items in clipboard history on windows" src="/static/5943b22bbb49e2802deb3e2cfd714760/09fc4/pin-history.jpg" srcset="/static/5943b22bbb49e2802deb3e2cfd714760/6f81f/pin-history.jpg 270w, /static/5943b22bbb49e2802deb3e2cfd714760/09fc4/pin-history.jpg 429w" sizes="(max-width: 429px) 100vw, 429px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <h2 id="mac-to-mac" style="position:relative;"><a href="#mac-to-mac" aria-label="mac to mac permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Mac to Mac</h2> <p>If you’re a Mac user and want to achieve the same, you can use the <a href="https://support.apple.com/en-au/HT209460#:~:text=On%20your%20Mac%3A%20Choose%20Apple,Handoff%2C%20then%20turn%20on%20Handoff.">Universal Clipboard</a>.</p> <p>It’s really simple, like we saw on windows setup.</p> <h2 id="windowsmaclinux-to-macwindowslinux" style="position:relative;"><a href="#windowsmaclinux-to-macwindowslinux" aria-label="windowsmaclinux to macwindowslinux permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Windows/Mac/Linux to Mac/Windows/Linux</h2> <p>If you use two different operating systems and want to simply share your content across, nothing works better than <a href="https://pastebin.com/">PASTEBIN</a>.</p> <p>This is a web tool that allows you to share your content across different devices with ease.</p> <h2 id="warning" style="position:relative;"><a href="#warning" aria-label="warning permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Warning</h2> <p>When using third party software whether it’s application or web app, never share secrets or your personal information.</p> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>We saw how to take some simple steps to increase our productivity and access any content we would like across our devices. Hope you benefit from this like I did and see you next time.</p><![CDATA[I've joined Microsoft as an Azure Technical Trainer 🗺️ 😍]]>https://yashints.dev/blog/2020/11/02/joining-microsofthttps://yashints.dev/blog/2020/11/02/joining-microsoftMon, 02 Nov 2020 00:00:00 GMT<p>The cat is out of the bag now, I’ve joined <a href="https://www.microsoft.com/">Microsoft</a> as an <strong>Azure Technical Trainer</strong>. Some of you might be wondering why, and if so, this post is for you. I’ve decided to write down why I’ve made this decision and a bit about my 15+ years journey from high school to where I am now.</p> <p>PS: We don’t have a Microsoft campus in Melbourne, but it didn’t prevent me photoshopping myself in 😜. Also, <strong>Satya Nadella</strong> was another motivation for me to join since we have a decent resemblance 😎.</p> <!--more--> <h2 id="background" style="position:relative;"><a href="#background" aria-label="background permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Background</h2> <p>I started to write small programs when my brother bought a PC back in 1998. It was running MS-DOS and the first program I wrote could print a pyramid with stars on the console and was written in <a href="https://en.wikipedia.org/wiki/QBasic#:~:text=QBasic%20is%20an%20integrated%20development,on%20demand%20within%20the%20IDE.">QBasic</a>. From then, I was always amazed by people who write programs which can help others write their own, and working at <a href="https://www.microsoft.com/">Microsoft</a> became one of my dream jobs.</p> <p>Later on, I progressed through high school, pre-uni and then uni when I started my journey as a software engineer. I’ve started with <a href="https://en.wikipedia.org/wiki/C%2B%2B">C++</a>, <a href="https://en.wikipedia.org/wiki/Turbo_Pascal">Turbo Pascal</a>, <a href="https://en.wikipedia.org/wiki/FoxPro">FoxPro</a>, <a href="https://en.wikipedia.org/wiki/Delphi_(software)">Delphi</a>, <a href="https://en.wikipedia.org/wiki/Active_Server_Pages">ASP Classic</a>, <a href="https://en.wikipedia.org/wiki/PHP">PHP</a>, and many other languages and ended up with, and finally <a href="https://en.wikipedia.org/wiki/ASP.NET_MVC">ASP.Net MVC</a>.</p> <p>Throughout those years I became really interested to web development and have been active in that area so far. Of course that wasn’t the only thing I picked up, I have written windows desktop apps with <a href="https://en.wikipedia.org/wiki/ASP.NET_Web_Forms">ASP.Net web forms</a> and <a href="https://en.wikipedia.org/wiki/Spring_Framework">Java Spring</a>, <a href="https://en.wikipedia.org/wiki/Java_Card">Java Card applets</a> to work with HSM and physical security devices, ActiveX, and many more I can’t even remember, not because I didn’t like them, but because I was really into learning new things and there were too many out there.</p> <p>I wasn’t born in a wealthy family, so I had work summers and other free times to earn enough to go through my studies for the rest of the year. And we don’t have big companies represented in Iran, so working for Microsoft was became a wish in my bucket list.</p> <h2 id="post-uni" style="position:relative;"><a href="#post-uni" aria-label="post uni permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Post uni</h2> <p>When I graduated from University with a Master’s degree in Information Security, I was hired by one of the well known software companies who were involved in banking industry. From there, I had jobs as software engineer, team lead and line manager and eventually I became the software engineering lead for one of the private banks’s PSP (payment service provider) company. But throughout all those years, I was on the lookout for an opportunity to migrate to another country and continue my professional career there.</p> <h2 id="migrating-to-australia" style="position:relative;"><a href="#migrating-to-australia" aria-label="migrating to australia permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Migrating to Australia</h2> <p>We considered Canada, US, and a few countries in Europe, but ended up pinning Australia on the map because of a few different reasons which suited our lifestyle and goals. So we sold/gave away most of our household items, rented out the apartment and packed our suitcases, jumped on a plane and ended up in Melbourne, Australia in 2015. I don’t want to go through how we got the Skilled Visa because it’s simply too long and brings back many not so good memories.</p> <h2 id="first-job-here" style="position:relative;"><a href="#first-job-here" aria-label="first job here permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>First job here</h2> <p>I immediately started applying for jobs here and without surprise, I was getting many calls, but not an actual opportunity that I liked. After one week, I had to bring down my expectations and start from scratch. I applied for a mid-level developer at a company and got in. This was after 3 weeks from our arrival and believe it or not is a record time for migrants to get a job.</p> <h2 id="moving-into-consulting-and-public-speaking" style="position:relative;"><a href="#moving-into-consulting-and-public-speaking" aria-label="moving into consulting and public speaking permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Moving into consulting and public speaking</h2> <p>I didn’t stay there for long, as I didn’t want to waste any time following my goals. So I got into a consulting firm and eventually joined <a href="https://www.linkedin.com/company/readify/?originalSubdomain=au">Readify (one of the best consulting firms in Australia)</a> back in 2016. Because of my love for knowledge sharing, I got into public speaking starting from local meetups ended up at international conferences around the world. I am super proud of what I’ve achieved throughout these years and owe a big part to Readify and later on Telstra Purple. However, I still had my bucket list getting dust and wasn’t enjoying what I was doing as my full time job.</p> <h2 id="decision-to-shift-to-developer-advocacy" style="position:relative;"><a href="#decision-to-shift-to-developer-advocacy" aria-label="decision to shift to developer advocacy permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Decision to shift to developer advocacy</h2> <p>I was doing conference talks, blogs, and was involved in development community which has been a real pleasure, but managing all of that while having a full time job was really tough. So I started to search for similar roles and came across developer advocacy. However, this not a role which is very well known in Australia apart from big companies like Microsoft, Amazon AWS, IBM etc and some smaller ones like Auth0 and Twilio. I had a few discussions with different people to get an idea of what’s required to be able to score one of those jobs, but didn’t get a chance to find and apply for one.</p> <h2 id="when-an-opportunity-presents-itself" style="position:relative;"><a href="#when-an-opportunity-presents-itself" aria-label="when an opportunity presents itself permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>When an opportunity presents itself</h2> <p>So I continued what I was doing, but still were on the lookout for something interesting which could help me do what I love to do. A few weeks back one of my friends who also works at Microsoft told me about a position on the Azure Technical Training team and I thought that’s something I would be really good at. It would be a bit of shift from web development, but the pros (working at <strong>Microsoft</strong>, sharing knowledge, and being close to what I love to do) convinced me to apply. I went through the interview and got an offer which made my year. This year has been really tough for me and my family and this event really helped us recover from these last few months of stress and anxiety.</p> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>So here I am, employed by my dream company, and doing what I love to do. It couldn’t have ended up better than this, I’ve already talked to my manager and he knows and supports my passion to be involved in development community, so this doesn’t mean I won’t be active on conferences and blog posts anymore. This amazing opportunity will help me grow in many ways as working at Microsoft and working with so many talented and amazing people would.</p> <p>I just hope this has inspired a few of you fellow developers out there to never give up hope and follow your dreams however distant and impossible they seem 🤘🏽 💪🏽.</p><![CDATA[Get started with Vue 3 and Tailwindcss]]>https://yashints.dev/blog/2020/10/22/vue-tailwindhttps://yashints.dev/blog/2020/10/22/vue-tailwindThu, 22 Oct 2020 00:00:00 GMT<p>Last week I wanted to setup a <a href="https://v3.vuejs.org/">Vue.js v3</a> app with <a href="https://tailwindcss.com/">Tailwindcss</a> and although many articles exists for that, I couldn’t get it done. The fact is that you need to use <a href="">postcss</a> to get your setup working, but with new version of <strong>Vue</strong>, the <code class="language-text">postcss</code> config file is not picked up. So after a few try and errors, I finally got it working and thought to jot down what I went through to make it easier for my future self, and hopefully a few of my fellow developers around the world.</p> <!--more--> <h2 id="vue-cli" style="position:relative;"><a href="#vue-cli" aria-label="vue cli permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Vue CLI</h2> <p>You can setup your <strong>Vue</strong> project with simply importing the script tag and start coding, but I normally like to use <a href="https://cli.vuejs.org/">Vue CLI</a> to get started because it takes care of the many things for me and gives a really good starting point.</p> <p>So let’s start by installing Vue CLI if you don’t have it already:</p> <div class="gatsby-code-button-container" data-toaster-id="95891346860226120000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`npm install -g @vue/cli # OR yarn global add @vue/cli`, `95891346860226120000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> -g @vue/cli <span class="token comment"># OR</span> <span class="token function">yarn</span> global <span class="token function">add</span> @vue/cli</code></pre></div> <p>This will install the Vue CLI for you and once that’s done, you’d be ready to create your project. If you already have CLI installed, make sure you update it first to get support for <em>Vue v3 preview</em>.</p> <h2 id="creating-the-project" style="position:relative;"><a href="#creating-the-project" aria-label="creating the project permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Creating the project</h2> <p>In order to create your project, you need to call the CLI and give your project name:</p> <div class="gatsby-code-button-container" data-toaster-id="41410295270910755000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`vue create vue-tailwindcss`, `41410295270910755000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">vue create vue-tailwindcss</code></pre></div> <p>This command will start the wizard and asks you what version of Vue you want to use and what additional options you want to have. </p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1080px; " > <span class="gatsby-resp-image-background-image" style="padding-bottom: 26.296296296296294%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAFABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAIDBf/EABQBAQAAAAAAAAAAAAAAAAAAAAL/2gAMAwEAAhADEAAAAcSQxcA//8QAFhAAAwAAAAAAAAAAAAAAAAAAAAEQ/9oACAEBAAEFAoj/xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAwEBPwFn/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAER/9oACAECAQE/AYx//8QAFBABAAAAAAAAAAAAAAAAAAAAEP/aAAgBAQAGPwJ//8QAGRAAAgMBAAAAAAAAAAAAAAAAAAERITFR/9oACAEBAAE/IU54JWZP/9oADAMBAAIAAwAAABD3z//EABURAQEAAAAAAAAAAAAAAAAAAAEA/9oACAEDAQE/EEjC3//EABYRAQEBAAAAAAAAAAAAAAAAAAEAEf/aAAgBAgEBPxACSdv/xAAbEAEAAgIDAAAAAAAAAAAAAAABACERMVGRwf/aAAgBAQABPxB9jpBA+RBczfM//9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Vue CLI wizard" title="Vue CLI wizard" src="/static/f1d31a73e389807ff13ceff8a58b79b0/47311/cli-wizard.jpg" srcset="/static/f1d31a73e389807ff13ceff8a58b79b0/6f81f/cli-wizard.jpg 270w, /static/f1d31a73e389807ff13ceff8a58b79b0/09d21/cli-wizard.jpg 540w, /static/f1d31a73e389807ff13ceff8a58b79b0/47311/cli-wizard.jpg 1080w, /static/f1d31a73e389807ff13ceff8a58b79b0/bb656/cli-wizard.jpg 1297w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </span></p> <p>You can choose between default seetings, or making a completely custom setup. I will normally choose custom which gives me more freedom as to what I want to setup.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1080px; " > <span class="gatsby-resp-image-background-image" style="padding-bottom: 28.148148148148145%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAGABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAEDBf/EABYBAQEBAAAAAAAAAAAAAAAAAAEAAv/aAAwDAQACEAMQAAABxpHNYn//xAAWEAEBAQAAAAAAAAAAAAAAAAAAATH/2gAIAQEAAQUCXH//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAUEAEAAAAAAAAAAAAAAAAAAAAQ/9oACAEBAAY/An//xAAYEAACAwAAAAAAAAAAAAAAAAAAARARYf/aAAgBAQABPyHRrh//2gAMAwEAAgADAAAAEPvv/8QAFREBAQAAAAAAAAAAAAAAAAAAARD/2gAIAQMBAT8QGf/EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABkQAQADAQEAAAAAAAAAAAAAAAEAETFhkf/aAAgBAQABPxBoxKYTJR32f//Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Vue CLI wizard" title="Vue CLI wizard" src="/static/1ca1c81a1e093f75c09a6ec363398937/47311/cli-custom.jpg" srcset="/static/1ca1c81a1e093f75c09a6ec363398937/6f81f/cli-custom.jpg 270w, /static/1ca1c81a1e093f75c09a6ec363398937/09d21/cli-custom.jpg 540w, /static/1ca1c81a1e093f75c09a6ec363398937/47311/cli-custom.jpg 1080w, /static/1ca1c81a1e093f75c09a6ec363398937/0047d/cli-custom.jpg 1620w, /static/1ca1c81a1e093f75c09a6ec363398937/274e1/cli-custom.jpg 2160w, /static/1ca1c81a1e093f75c09a6ec363398937/ab590/cli-custom.jpg 2337w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </span></p> <p>From here press <kbd>Entre</kbd> on <strong>Choose Vue version</strong>, and select <strong>3.x (Preview)</strong>.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1080px; " > <span class="gatsby-resp-image-background-image" style="padding-bottom: 16.296296296296294%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAADABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAMF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAcSxZIH/xAAXEAEAAwAAAAAAAAAAAAAAAAAAAQIx/9oACAEBAAEFAlU7/8QAFREBAQAAAAAAAAAAAAAAAAAAEEH/2gAIAQMBAT8Bp//EABURAQEAAAAAAAAAAAAAAAAAABBB/9oACAECAQE/AYf/xAAUEAEAAAAAAAAAAAAAAAAAAAAQ/9oACAEBAAY/An//xAAXEAADAQAAAAAAAAAAAAAAAAAAATER/9oACAEBAAE/IdZaLH//2gAMAwEAAgADAAAAEAg//8QAFhEBAQEAAAAAAAAAAAAAAAAAAAEx/9oACAEDAQE/EIXX/8QAFhEAAwAAAAAAAAAAAAAAAAAAARAx/9oACAECAQE/EDS//8QAGhAAAgIDAAAAAAAAAAAAAAAAASEAERBBof/aAAgBAQABPxBwfIViTvWN/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Vue CLI wizard" title="Vue CLI wizard" src="/static/4fd95e31fdc584eb3ee5c391f22342a4/47311/cli-vue3.jpg" srcset="/static/4fd95e31fdc584eb3ee5c391f22342a4/6f81f/cli-vue3.jpg 270w, /static/4fd95e31fdc584eb3ee5c391f22342a4/09d21/cli-vue3.jpg 540w, /static/4fd95e31fdc584eb3ee5c391f22342a4/47311/cli-vue3.jpg 1080w, /static/4fd95e31fdc584eb3ee5c391f22342a4/0047d/cli-vue3.jpg 1620w, /static/4fd95e31fdc584eb3ee5c391f22342a4/05ac4/cli-vue3.jpg 1753w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </span></p> <p>I would normally choose <a href="https://www.typescriptlang.org/">TypeScript</a>, <a href="https://babeljs.io/">Babel</a>, Linter, Unit and E2E testing optiuons, but feel free to setup how you like.</p> <p>When it’s done go navigate into the folder or open it up with your editor of choice. Mince is <a href="https://code.visualstudio.com/">VS Code</a>.</p> <h2 id="installing-the-required-dependencies" style="position:relative;"><a href="#installing-the-required-dependencies" aria-label="installing the required dependencies permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Installing the required dependencies</h2> <p>At this point we need to install Tailwindcss:</p> <div class="gatsby-code-button-container" data-toaster-id="40755341358561440000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`npm install tailwindcss`, `40755341358561440000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> tailwindcss</code></pre></div> <h2 id="create-your-style-file" style="position:relative;"><a href="#create-your-style-file" aria-label="create your style file permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Create your style file</h2> <p>At this stage you’re ready to create your style file. I will put it next to my <code class="language-text">main.js</code> for convinience. </p> <p><img src="./main-css.jpg" alt="Main style file"></p> <p>Don’t forget to import it inside your main.js file:</p> <div class="gatsby-code-button-container" data-toaster-id="74032267765075210000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`import &quot;./main.css&quot;; // ...`, `74032267765075210000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token string">"./main.css"</span><span class="token punctuation">;</span> <span class="token comment">// ...</span></code></pre></div> <p>And now is the time to import the <strong>Tailwincss</strong> base and components in our <code class="language-text">css</code> file:</p> <div class="gatsby-code-button-container" data-toaster-id="2303169003145644300" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`/* src/main.css */ @import &quot;tailwindcss/base&quot;; @import &quot;tailwindcss/components&quot;; @import &quot;tailwindcss/utilities&quot;;`, `2303169003145644300`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token comment">/* src/main.css */</span> <span class="token atrule"><span class="token rule">@import</span> <span class="token string">"tailwindcss/base"</span><span class="token punctuation">;</span></span> <span class="token atrule"><span class="token rule">@import</span> <span class="token string">"tailwindcss/components"</span><span class="token punctuation">;</span></span> <span class="token atrule"><span class="token rule">@import</span> <span class="token string">"tailwindcss/utilities"</span><span class="token punctuation">;</span></span></code></pre></div> <h2 id="postcss-configuration" style="position:relative;"><a href="#postcss-configuration" aria-label="postcss configuration permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Postcss configuration</h2> <p>Many articles tell you to create a <code class="language-text">postcss.config.js</code> or <code class="language-text">.postcssrc.js</code> and set your config there, but with the new version of Vue CLI this doesn’t get picked up. For this part we simply need to update our <code class="language-text">package.json</code> file:</p> <div class="gatsby-code-button-container" data-toaster-id="62737504950705490000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`&quot;postcss&quot;: { &quot;plugins&quot;: { &quot;tailwindcss&quot;: {}, &quot;autoprefixer&quot;: {} } }`, `62737504950705490000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"postcss"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"plugins"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"tailwindcss"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"autoprefixer"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div> <h2 id="import-tailwindcss-components" style="position:relative;"><a href="#import-tailwindcss-components" aria-label="import tailwindcss components permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Import Tailwindcss components</h2> <p>You’re ready to use the Tailwindcss components now. So open up your hello-world.vue file and paste this code from <a href="https://tailwindui.com/preview">their free gallery</a> in:</p> <div class="gatsby-code-button-container" data-toaster-id="26475093783762694000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<!-- Tailwind UI components require Tailwind CSS v1.8 and the @tailwindcss/ui plugin. Read the documentation to get started: https://tailwindui.com/documentation --> <div class=&quot;relative bg-white overflow-hidden&quot;> <div class=&quot;max-w-screen-xl mx-auto&quot;> <div class=&quot;relative z-10 pb-8 bg-white sm:pb-16 md:pb-20 lg:max-w-2xl lg:w-full lg:pb-28 xl:pb-32&quot;> <svg class=&quot;hidden lg:block absolute right-0 inset-y-0 h-full w-48 text-white transform translate-x-1/2&quot; fill=&quot;currentColor&quot; viewBox=&quot;0 0 100 100&quot; preserveAspectRatio=&quot;none&quot;> <polygon points=&quot;50,0 100,0 50,100 0,100&quot; /> </svg> <div class=&quot;relative pt-6 px-4 sm:px-6 lg:px-8&quot;> <nav class=&quot;relative flex items-center justify-between sm:h-10 lg:justify-start&quot;> <div class=&quot;flex items-center flex-grow flex-shrink-0 lg:flex-grow-0&quot;> <div class=&quot;flex items-center justify-between w-full md:w-auto&quot;> <a href=&quot;#&quot; aria-label=&quot;Home&quot;> <img class=&quot;h-8 w-auto sm:h-10&quot; src=&quot;https://tailwindui.com/img/logos/workflow-mark-on-white.svg&quot; alt=&quot;Logo&quot;> </a> <div class=&quot;-mr-2 flex items-center md:hidden&quot;> <button type=&quot;button&quot; class=&quot;inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 focus:text-gray-500 transition duration-150 ease-in-out&quot; id=&quot;main-menu&quot; aria-label=&quot;Main menu&quot; aria-haspopup=&quot;true&quot;> <svg class=&quot;h-6 w-6&quot; stroke=&quot;currentColor&quot; fill=&quot;none&quot; viewBox=&quot;0 0 24 24&quot;> <path stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; stroke-width=&quot;2&quot; d=&quot;M4 6h16M4 12h16M4 18h16&quot; /> </svg> </button> </div> </div> </div> <div class=&quot;hidden md:block md:ml-10 md:pr-4&quot;> <a href=&quot;#&quot; class=&quot;font-medium text-gray-500 hover:text-gray-900 transition duration-150 ease-in-out&quot;>Product</a> <a href=&quot;#&quot; class=&quot;ml-8 font-medium text-gray-500 hover:text-gray-900 transition duration-150 ease-in-out&quot;>Features</a> <a href=&quot;#&quot; class=&quot;ml-8 font-medium text-gray-500 hover:text-gray-900 transition duration-150 ease-in-out&quot;>Marketplace</a> <a href=&quot;#&quot; class=&quot;ml-8 font-medium text-gray-500 hover:text-gray-900 transition duration-150 ease-in-out&quot;>Company</a> <a href=&quot;#&quot; class=&quot;ml-8 font-medium text-indigo-600 hover:text-indigo-900 transition duration-150 ease-in-out&quot;>Log in</a> </div> </nav> </div> <!-- Mobile menu, show/hide based on menu open state. Entering: &quot;duration-150 ease-out&quot; From: &quot;opacity-0 scale-95&quot; To: &quot;opacity-100 scale-100&quot; Leaving: &quot;duration-100 ease-in&quot; From: &quot;opacity-100 scale-100&quot; To: &quot;opacity-0 scale-95&quot; --> <div class=&quot;absolute top-0 inset-x-0 p-2 transition transform origin-top-right md:hidden&quot;> <div class=&quot;rounded-lg shadow-md&quot;> <div class=&quot;rounded-lg bg-white shadow-xs overflow-hidden&quot; role=&quot;menu&quot; aria-orientation=&quot;vertical&quot; aria-labelledby=&quot;main-menu&quot;> <div class=&quot;px-5 pt-4 flex items-center justify-between&quot;> <div> <img class=&quot;h-8 w-auto&quot; src=&quot;https://tailwindui.com/img/logos/workflow-mark-on-white.svg&quot; alt=&quot;&quot;> </div> <div class=&quot;-mr-2&quot;> <button type=&quot;button&quot; class=&quot;inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 focus:text-gray-500 transition duration-150 ease-in-out&quot; aria-label=&quot;Close menu&quot;> <svg class=&quot;h-6 w-6&quot; stroke=&quot;currentColor&quot; fill=&quot;none&quot; viewBox=&quot;0 0 24 24&quot;> <path stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; stroke-width=&quot;2&quot; d=&quot;M6 18L18 6M6 6l12 12&quot; /> </svg> </button> </div> </div> <div class=&quot;px-2 pt-2 pb-3&quot;> <a href=&quot;#&quot; class=&quot;block px-3 py-2 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50 focus:outline-none focus:text-gray-900 focus:bg-gray-50 transition duration-150 ease-in-out&quot; role=&quot;menuitem&quot;>Product</a> <a href=&quot;#&quot; class=&quot;mt-1 block px-3 py-2 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50 focus:outline-none focus:text-gray-900 focus:bg-gray-50 transition duration-150 ease-in-out&quot; role=&quot;menuitem&quot;>Features</a> <a href=&quot;#&quot; class=&quot;mt-1 block px-3 py-2 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50 focus:outline-none focus:text-gray-900 focus:bg-gray-50 transition duration-150 ease-in-out&quot; role=&quot;menuitem&quot;>Marketplace</a> <a href=&quot;#&quot; class=&quot;mt-1 block px-3 py-2 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50 focus:outline-none focus:text-gray-900 focus:bg-gray-50 transition duration-150 ease-in-out&quot; role=&quot;menuitem&quot;>Company</a> </div> <div> <a href=&quot;#&quot; class=&quot;block w-full px-5 py-3 text-center font-medium text-indigo-600 bg-gray-50 hover:bg-gray-100 hover:text-indigo-700 focus:outline-none focus:bg-gray-100 focus:text-indigo-700 transition duration-150 ease-in-out&quot; role=&quot;menuitem&quot;> Log in </a> </div> </div> </div> </div> <main class=&quot;mt-10 mx-auto max-w-screen-xl px-4 sm:mt-12 sm:px-6 md:mt-16 lg:mt-20 lg:px-8 xl:mt-28&quot;> <div class=&quot;sm:text-center lg:text-left&quot;> <h2 class=&quot;text-4xl tracking-tight leading-10 font-extrabold text-gray-900 sm:text-5xl sm:leading-none md:text-6xl&quot;> Data to enrich your <br class=&quot;xl:hidden&quot;> <span class=&quot;text-indigo-600&quot;>online business</span> </h2> <p class=&quot;mt-3 text-base text-gray-500 sm:mt-5 sm:text-lg sm:max-w-xl sm:mx-auto md:mt-5 md:text-xl lg:mx-0&quot;> Anim aute id magna aliqua ad ad non deserunt sunt. Qui irure qui lorem cupidatat commodo. Elit sunt amet fugiat veniam occaecat fugiat aliqua. </p> <div class=&quot;mt-5 sm:mt-8 sm:flex sm:justify-center lg:justify-start&quot;> <div class=&quot;rounded-md shadow&quot;> <a href=&quot;#&quot; class=&quot;w-full flex items-center justify-center px-8 py-3 border border-transparent text-base leading-6 font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:shadow-outline-indigo transition duration-150 ease-in-out md:py-4 md:text-lg md:px-10&quot;> Get started </a> </div> <div class=&quot;mt-3 sm:mt-0 sm:ml-3&quot;> <a href=&quot;#&quot; class=&quot;w-full flex items-center justify-center px-8 py-3 border border-transparent text-base leading-6 font-medium rounded-md text-indigo-700 bg-indigo-100 hover:text-indigo-600 hover:bg-indigo-50 focus:outline-none focus:shadow-outline-indigo focus:border-indigo-300 transition duration-150 ease-in-out md:py-4 md:text-lg md:px-10&quot;> Live demo </a> </div> </div> </div> </main> </div> </div> <div class=&quot;lg:absolute lg:inset-y-0 lg:right-0 lg:w-1/2&quot;> <img class=&quot;h-56 w-full object-cover sm:h-72 md:h-96 lg:w-full lg:h-full&quot; src=&quot;https://images.unsplash.com/photo-1551434678-e076c223a692?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2850&q=80&quot; alt=&quot;&quot;> </div> </div>`, `26475093783762694000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token comment">&lt;!-- Tailwind UI components require Tailwind CSS v1.8 and the @tailwindcss/ui plugin. Read the documentation to get started: https://tailwindui.com/documentation --></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>relative bg-white overflow-hidden<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>max-w-screen-xl mx-auto<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>relative z-10 pb-8 bg-white sm:pb-16 md:pb-20 lg:max-w-2xl lg:w-full lg:pb-28 xl:pb-32<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>svg</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>hidden lg:block absolute right-0 inset-y-0 h-full w-48 text-white transform translate-x-1/2<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>currentColor<span class="token punctuation">"</span></span> <span class="token attr-name">viewBox</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0 0 100 100<span class="token punctuation">"</span></span> <span class="token attr-name">preserveAspectRatio</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>none<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>polygon</span> <span class="token attr-name">points</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>50,0 100,0 50,100 0,100<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>svg</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>relative pt-6 px-4 sm:px-6 lg:px-8<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>nav</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>relative flex items-center justify-between sm:h-10 lg:justify-start<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex items-center flex-grow flex-shrink-0 lg:flex-grow-0<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>flex items-center justify-between w-full md:w-auto<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#<span class="token punctuation">"</span></span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Home<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>h-8 w-auto sm:h-10<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://tailwindui.com/img/logos/workflow-mark-on-white.svg<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Logo<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-mr-2 flex items-center md:hidden<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 focus:text-gray-500 transition duration-150 ease-in-out<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>main-menu<span class="token punctuation">"</span></span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Main menu<span class="token punctuation">"</span></span> <span class="token attr-name">aria-haspopup</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>svg</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>h-6 w-6<span class="token punctuation">"</span></span> <span class="token attr-name">stroke</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>currentColor<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>none<span class="token punctuation">"</span></span> <span class="token attr-name">viewBox</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0 0 24 24<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>path</span> <span class="token attr-name">stroke-linecap</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>round<span class="token punctuation">"</span></span> <span class="token attr-name">stroke-linejoin</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>round<span class="token punctuation">"</span></span> <span class="token attr-name">stroke-width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>2<span class="token punctuation">"</span></span> <span class="token attr-name">d</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>M4 6h16M4 12h16M4 18h16<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>svg</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>hidden md:block md:ml-10 md:pr-4<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>font-medium text-gray-500 hover:text-gray-900 transition duration-150 ease-in-out<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Product<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>ml-8 font-medium text-gray-500 hover:text-gray-900 transition duration-150 ease-in-out<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Features<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>ml-8 font-medium text-gray-500 hover:text-gray-900 transition duration-150 ease-in-out<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Marketplace<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>ml-8 font-medium text-gray-500 hover:text-gray-900 transition duration-150 ease-in-out<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Company<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>ml-8 font-medium text-indigo-600 hover:text-indigo-900 transition duration-150 ease-in-out<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Log in<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>nav</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token comment">&lt;!-- Mobile menu, show/hide based on menu open state. Entering: "duration-150 ease-out" From: "opacity-0 scale-95" To: "opacity-100 scale-100" Leaving: "duration-100 ease-in" From: "opacity-100 scale-100" To: "opacity-0 scale-95" --></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>absolute top-0 inset-x-0 p-2 transition transform origin-top-right md:hidden<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>rounded-lg shadow-md<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>rounded-lg bg-white shadow-xs overflow-hidden<span class="token punctuation">"</span></span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>menu<span class="token punctuation">"</span></span> <span class="token attr-name">aria-orientation</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>vertical<span class="token punctuation">"</span></span> <span class="token attr-name">aria-labelledby</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>main-menu<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>px-5 pt-4 flex items-center justify-between<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>h-8 w-auto<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://tailwindui.com/img/logos/workflow-mark-on-white.svg<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-mr-2<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 focus:text-gray-500 transition duration-150 ease-in-out<span class="token punctuation">"</span></span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Close menu<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>svg</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>h-6 w-6<span class="token punctuation">"</span></span> <span class="token attr-name">stroke</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>currentColor<span class="token punctuation">"</span></span> <span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>none<span class="token punctuation">"</span></span> <span class="token attr-name">viewBox</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0 0 24 24<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>path</span> <span class="token attr-name">stroke-linecap</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>round<span class="token punctuation">"</span></span> <span class="token attr-name">stroke-linejoin</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>round<span class="token punctuation">"</span></span> <span class="token attr-name">stroke-width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>2<span class="token punctuation">"</span></span> <span class="token attr-name">d</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>M6 18L18 6M6 6l12 12<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>svg</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>px-2 pt-2 pb-3<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>block px-3 py-2 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50 focus:outline-none focus:text-gray-900 focus:bg-gray-50 transition duration-150 ease-in-out<span class="token punctuation">"</span></span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>menuitem<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Product<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mt-1 block px-3 py-2 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50 focus:outline-none focus:text-gray-900 focus:bg-gray-50 transition duration-150 ease-in-out<span class="token punctuation">"</span></span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>menuitem<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Features<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mt-1 block px-3 py-2 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50 focus:outline-none focus:text-gray-900 focus:bg-gray-50 transition duration-150 ease-in-out<span class="token punctuation">"</span></span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>menuitem<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Marketplace<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mt-1 block px-3 py-2 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50 focus:outline-none focus:text-gray-900 focus:bg-gray-50 transition duration-150 ease-in-out<span class="token punctuation">"</span></span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>menuitem<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Company<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>block w-full px-5 py-3 text-center font-medium text-indigo-600 bg-gray-50 hover:bg-gray-100 hover:text-indigo-700 focus:outline-none focus:bg-gray-100 focus:text-indigo-700 transition duration-150 ease-in-out<span class="token punctuation">"</span></span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>menuitem<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Log in <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>main</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mt-10 mx-auto max-w-screen-xl px-4 sm:mt-12 sm:px-6 md:mt-16 lg:mt-20 lg:px-8 xl:mt-28<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sm:text-center lg:text-left<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text-4xl tracking-tight leading-10 font-extrabold text-gray-900 sm:text-5xl sm:leading-none md:text-6xl<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Data to enrich your <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>br</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>xl:hidden<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text-indigo-600<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>online business<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mt-3 text-base text-gray-500 sm:mt-5 sm:text-lg sm:max-w-xl sm:mx-auto md:mt-5 md:text-xl lg:mx-0<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Anim aute id magna aliqua ad ad non deserunt sunt. Qui irure qui lorem cupidatat commodo. Elit sunt amet fugiat veniam occaecat fugiat aliqua. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mt-5 sm:mt-8 sm:flex sm:justify-center lg:justify-start<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>rounded-md shadow<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>w-full flex items-center justify-center px-8 py-3 border border-transparent text-base leading-6 font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:shadow-outline-indigo transition duration-150 ease-in-out md:py-4 md:text-lg md:px-10<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Get started <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mt-3 sm:mt-0 sm:ml-3<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>w-full flex items-center justify-center px-8 py-3 border border-transparent text-base leading-6 font-medium rounded-md text-indigo-700 bg-indigo-100 hover:text-indigo-600 hover:bg-indigo-50 focus:outline-none focus:shadow-outline-indigo focus:border-indigo-300 transition duration-150 ease-in-out md:py-4 md:text-lg md:px-10<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Live demo <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>main</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>lg:absolute lg:inset-y-0 lg:right-0 lg:w-1/2<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>h-56 w-full object-cover sm:h-72 md:h-96 lg:w-full lg:h-full<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://images.unsplash.com/photo-1551434678-e076c223a692?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=crop&amp;w=2850&amp;q=80<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code></pre></div> <h2 id="run-the-application" style="position:relative;"><a href="#run-the-application" aria-label="run the application permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Run the application</h2> <p>You’re all set, run <code class="language-text">npm run serve</code> and when the CLI is finished compiling the app, open a browser window and head to <code class="language-text">https://localhost:8080</code> to see the <code class="language-text">Tailwindcss</code> component:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1080px; " > <span class="gatsby-resp-image-background-image" style="padding-bottom: 46.666666666666664%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAJABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAQFAv/EABYBAQEBAAAAAAAAAAAAAAAAAAABAv/aAAwDAQACEAMQAAABtZYVJRMM3//EABsQAAICAwEAAAAAAAAAAAAAAAECAAMSITEz/9oACAEBAAEFAtks+Mdlcy3l3p//xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAwEBPwFX/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAER/9oACAECAQE/Aax//8QAHRAAAgAHAQAAAAAAAAAAAAAAAAEQERIhImGBof/aAAgBAQAGPwKz8OFWSnuDGf/EABsQAQACAgMAAAAAAAAAAAAAAAEAESAhMWFx/9oACAEBAAE/IbYBpjdE9dwIlBxYrCb/2gAMAwEAAgADAAAAEATv/8QAFhEAAwAAAAAAAAAAAAAAAAAAAAER/9oACAEDAQE/EEqUf//EABURAQEAAAAAAAAAAAAAAAAAAAEQ/9oACAECAQE/EFH/xAAbEAEBAAIDAQAAAAAAAAAAAAABEQAQITGBof/aAAgBAQABPxA6iJFcY9QoUBarxMIuFTS6k818Rof/2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Tailwindcss components" title="Tailwindcss components" src="/static/4e8e031d40bfbb571c317c9f66f4233a/47311/tailwindcss-components.jpg" srcset="/static/4e8e031d40bfbb571c317c9f66f4233a/6f81f/tailwindcss-components.jpg 270w, /static/4e8e031d40bfbb571c317c9f66f4233a/09d21/tailwindcss-components.jpg 540w, /static/4e8e031d40bfbb571c317c9f66f4233a/47311/tailwindcss-components.jpg 1080w, /static/4e8e031d40bfbb571c317c9f66f4233a/0047d/tailwindcss-components.jpg 1620w, /static/4e8e031d40bfbb571c317c9f66f4233a/b53dc/tailwindcss-components.jpg 2038w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </span></p> <h2 id="customisation" style="position:relative;"><a href="#customisation" aria-label="customisation permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Customisation</h2> <p>If you want to customise any of the default styles, you need to modify the theme. To do so, run:</p> <div class="gatsby-code-button-container" data-toaster-id="87627354059295490000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`npx tailwind init`, `87627354059295490000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">npx tailwind init</code></pre></div> <p>This will create a <code class="language-text">tailwind.config.js</code> file for you in the root of your directory. To demo an example customisation, let’s say we want to add some space between the photo and the right hand side of the page. Currently the photo is having an <code class="language-text">position:absolute</code> and <code class="language-text">right:0</code> because it has the <code class="language-text">lg:right-0</code> class.</p> <p>So we want to add a new class which has <code class="language-text">10%</code> margin on the right hand side of the image. For that to work, we will need below code in our <code class="language-text">tailwindcss.config.js</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="31180829670958076000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`module.exports = { future: { // removeDeprecatedGapUtilities: true, // purgeLayersByDefault: true, }, purge: [], theme: { inset: { '0': 0, auto: 'auto', '1/10': '10%', }, extend: {}, }, variants: {}, plugins: [], }`, `31180829670958076000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span> future<span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token comment">// removeDeprecatedGapUtilities: true,</span> <span class="token comment">// purgeLayersByDefault: true,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> purge<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> theme<span class="token operator">:</span> <span class="token punctuation">{</span> inset<span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string">'0'</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> auto<span class="token operator">:</span> <span class="token string">'auto'</span><span class="token punctuation">,</span> <span class="token string">'1/10'</span><span class="token operator">:</span> <span class="token string">'10%'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> extend<span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> variants<span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> plugins<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">}</span></code></pre></div> <p>Pay attention that I’ve added a <code class="language-text">1/10</code> with the value of <code class="language-text">10%</code> which we can use. Now all we need to do is to add <code class="language-text">lg:right-1/10</code> to the image container which pushes the image to the left by <em>10%</em>:</p> <div class="gatsby-code-button-container" data-toaster-id="91740066319069970000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<div class=&quot;lg:absolute lg:inset-y-0 lg:right-1/10 lg:w-1/2&quot;> </div>`, `91740066319069970000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>lg:absolute lg:inset-y-0 lg:right-1/10 lg:w-1/2<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code></pre></div> <p>And now it should look like this:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1080px; " > <span class="gatsby-resp-image-background-image" style="padding-bottom: 32.96296296296297%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAHABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAUE/8QAFAEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAABuzgdgT//xAAZEAEAAgMAAAAAAAAAAAAAAAADAAIREiH/2gAIAQEAAQUC7lkg23L/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAgEBPwFn/8QAGBAAAwEBAAAAAAAAAAAAAAAAAAECESH/2gAIAQEABj8CMa5hNH//xAAXEAEBAQEAAAAAAAAAAAAAAAABEQBB/9oACAEBAAE/IQq1mdLbVR7osSm//9oADAMBAAIAAwAAABB7z//EABYRAQEBAAAAAAAAAAAAAAAAAAEQQf/aAAgBAwEBPxANn//EABURAQEAAAAAAAAAAAAAAAAAAAEQ/9oACAECAQE/EFP/xAAaEAACAwEBAAAAAAAAAAAAAAABEQAhQTHB/9oACAEBAAE/EGBdoUphUSUFhasgiAHNvleT/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Customise Tailwindcss" title="Customise Tailwindcss" src="/static/78948c2b9fef1b25d1e12a50a4324ad8/47311/tailwind-customise.jpg" srcset="/static/78948c2b9fef1b25d1e12a50a4324ad8/6f81f/tailwind-customise.jpg 270w, /static/78948c2b9fef1b25d1e12a50a4324ad8/09d21/tailwind-customise.jpg 540w, /static/78948c2b9fef1b25d1e12a50a4324ad8/47311/tailwind-customise.jpg 1080w, /static/78948c2b9fef1b25d1e12a50a4324ad8/0047d/tailwind-customise.jpg 1620w, /static/78948c2b9fef1b25d1e12a50a4324ad8/274e1/tailwind-customise.jpg 2160w, /static/78948c2b9fef1b25d1e12a50a4324ad8/375d1/tailwind-customise.jpg 3267w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </span></p> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>We saw how to add <code class="language-text">Tailwindcss</code> library to our Vue 3 application created by Vue CLI. Hopefully this will help some of you out there facing the same issue as me. See you next time 👏🏽.</p> <p>You can find the code in my <a href="https://github.com/yashints/Vue-Tailwind">GitHub repository</a>.</p><![CDATA[Do you know about PowerToy Utilities? 💪🏻]]>https://yashints.dev/blog/2020/10/09/powertoyshttps://yashints.dev/blog/2020/10/09/powertoysFri, 09 Oct 2020 00:00:00 GMT<p>If you’re a windows user like me, you might have heard of PowerToys Utilities from Microsoft. They are a set of utilities which come handy in many situations, but not many people know and use them. So I thought let’s write how and when I use them to help other people be more efficient too.</p> <!--more--> <h2 id="powertoys-utilities" style="position:relative;"><a href="#powertoys-utilities" aria-label="powertoys utilities permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>PowerToys utilities</h2> <p><a href="https://github.com/microsoft/PowerToys">Microsoft PowerToys</a> are a set of small applications which helps windows users streamline their day to day activities and windows experience for greater productivity. However, these are not new. There were a set of tools in <a href="https://en.wikipedia.org/wiki/Microsoft_PowerToys">Widows 95</a> (yes I’m that old) which inspired this project.</p> <h3 id="installation" style="position:relative;"><a href="#installation" aria-label="installation permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Installation</h3> <p>Simply head to the <a href="https://github.com/microsoft/PowerToys/releases/">Downloading and Release notes</a> section on their GitHub repository, download the version you’re after and install it using its installer.</p> <p>The latest version as of writing this article is <a href="https://github.com/microsoft/PowerToys/releases/download/v0.23.0/PowerToysSetup-0.23.0-x64.exe">v0.23.0</a>. Once you get it installed, it will update itself on a regular basis.</p> <p>So let’s see what are these and how you can use them.</p> <h3 id="color-picker" style="position:relative;"><a href="#color-picker" aria-label="color picker permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Color picker</h3> <p><a href="https://aka.ms/PowerToysOverview_ColorPicker">Color Picker</a> is a handy little tool which allows you to pick a color from anywhere on your screen. As a web developer there are many times when I want to get the hex or rgb value of a background color, border, or other areas.</p> <p>I used to use browser DevTools, but they only help you within the browser and if you want something from a document, picture or other files on your file system, then this tool will come in handy.</p> <p>If you haven’t customised the default shortcuts, press <kbd>Win</kbd> + <kbd>Shift</kbd> + <kbd>C</kbd> to open the picker. Once opened, you can use your mouse scroll to zoom in and left click to copy the value to your clipboard.</p> <p><img src="/b718c42b2982d179f52fd2a406561e5e/colorpicker.gif" alt="PowerToys color picker"></p> <h3 id="fancy-zones" style="position:relative;"><a href="#fancy-zones" aria-label="fancy zones permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Fancy zones</h3> <p><a href="https://aka.ms/PowerToysOverview_FancyZones">Fancy Zones</a> allows you to create complex window layouts and quickly position your windows into those. This comes really handy if you have a super wide monitor setup.</p> <p>To open it, press <kbd>Win</kbd> + <kbd>`</kbd> and select your desired layout from the opened window. Once selected you can arrange your windows into those areas by pressing <kbd>Win</kbd> + <kbd>⬅</kbd> or <kbd>Win</kbd> + <kbd>➡</kbd>.</p> <img src="/6aaf1ac433744a0b72f020a3661163f0/fancyzones.gif" alt="Fancy Zones from windows PowerToys" loading="lazy"> <blockquote> <p>💡 If the arrow keys didn’t work for you, simply select the option to override windows shortcuts in the settings. You can access the settings from clicking the PowerToys icon in your toolbar.</p> </blockquote> <h3 id="file-explorer-add-ons" style="position:relative;"><a href="#file-explorer-add-ons" aria-label="file explorer add ons permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>File explorer add-ons</h3> <p><a href="https://aka.ms/PowerToysOverview_FileExplorerAddOns">File Explorer add-ons</a> will enable SVG icon rendering and markdown preview for your file explorer. To see your preview pane simply click the view menu and click the preview pane.</p> <img src="/5df9c43c0ceda88fd1da28bc6819816d/fileexploreraddons.gif" alt="Fancy Zones from windows PowerToys" loading="lazy"> <h3 id="image-resizer" style="position:relative;"><a href="#image-resizer" aria-label="image resizer permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Image resizer</h3> <p><a href="https://aka.ms/PowerToysOverview_ImageResizer">Image Resizer</a> is a really cool shell extension which allows you to quickly resize images. Simply right click on your image or images and resize them instantly.</p> <img src="/296d47745d0282bf1af22655d3f208ac/imageresizer.gif" alt="Fancy Zones from windows PowerToys" loading="lazy"> <h3 id="keyboard-manager" style="position:relative;"><a href="#keyboard-manager" aria-label="keyboard manager permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>keyboard manager</h3> <p>Keyboard manager allows you to create your own keyboard layout to increase your productivity. You can map keys and mix them however you like, of course you would need a keyboard with detachable key caps for a better use.</p> <p>Open PowerToys settings and click on keyboard manager menu. First thing first, make sure it’s enabled.</p> <p><strong>Remap keys</strong></p> <p>If you want to remap a key, click on the remap keys, then click <kbd>+</kbd> button to add a key and then select what key you want that mapped to.</p> <img src="/11bff19abe860f5004a998896c049814/remapkeys.gif" alt="Keyboard manager remap key" loading="lazy"> <p>You can also map a single key to a shortcut, for example map <kbd>V</kbd> to <kbd>Ctrl</kbd> + <kbd>V</kbd>.</p> <blockquote> <p>💡 Just remember that when you map a key to a shortcut, the combination remains even as part of other key presses. So if you’ve mapped <kbd>V</kbd> as above, then pressing <kbd>Ctrl</kbd> + <kbd>V</kbd> now means you’ve pressed <kbd>Ctrl</kbd> + <kbd>V</kbd> + <kbd>V</kbd>.</p> </blockquote> <p><strong>Remap shortcuts</strong></p> <p>You can map shortcuts as well, to do so, click on the <em>remap a shortcut</em> button and follow the same procedure. You can click on type button to press multiple keys and at the end you can specify which application this shortcut remap applies to.</p> <img src="/4f1086cf89d03789fab0486b896b590e/shortcutremap.gif" alt="Keyboard manager remap key" loading="lazy"> <h3 id="powerrename" style="position:relative;"><a href="#powerrename" aria-label="powerrename permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>PowerRename</h3> <p><a href="https://aka.ms/PowerToysOverview_PowerRename">PowerRename</a> is another shell extension for balk renaming of files which offers search and replace and supports regex.</p> <p>Select and right click on multiple files or folders, then click <strong>PowerRename</strong>. From the opened dialog, select your desired options and once you’re happy, click rename.</p> <img src="/63b31fade1bf4db30915571eac64025d/renamer.gif" alt="Keyboard manager remap key" loading="lazy"> <h3 id="powertoys-run" style="position:relative;"><a href="#powertoys-run" aria-label="powertoys run permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>PowerToys run</h3> <p>This one is my favourite. It brings back the memories of the days we used to install add-ons on windows XP and 7 to add these sort of functionalities. First, make sure it’s enabled in the settings, and then press <kbd>Alt</kbd> + <kbd>Space</kbd>. A pop up will open and you can search for your application.</p> <blockquote> <p>💡 Since I use this shortcut to select my open window to be able to move it between my monitors, I’ve set my shortcut to <kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>Space</kbd>.</p> </blockquote> <h3 id="shortcut-guide" style="position:relative;"><a href="#shortcut-guide" aria-label="shortcut guide permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Shortcut guide</h3> <p><a href="https://aka.ms/PowerToysOverview_ShortcutGuide">Shortcut guide</a> is a quick and easy way to savailable shortcuts for the current state of the desktop. You can open it by pressing and holding down your <kbd>Win</kbd> key for 1 second.</p> <img src="/671f38fe4b784f855731785a559aeeac/shortcutguide.gif" alt="Keyboard manager remap key" loading="lazy"> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>Hopefully these tools will help you as much as they helped me. Have a great weekend ahead and till next article 👋🏻.</p><![CDATA[Find an item in an array with the new 'findIndex' method 🔎]]>https://yashints.dev/blog/2020/10/05/array-findindexhttps://yashints.dev/blog/2020/10/05/array-findindexMon, 05 Oct 2020 00:00:00 GMT<p>Searching for items in an array has been the point of discussion for many years and debate on what is the best and optimum way for searching for objects has had many solutions, some effective and some not.</p> <p>However, with the all new <code class="language-text">findIndex</code> method on <code class="language-text">Array.prototype</code> you have the flexibility to search for objects using your own comparison callback method.</p> <!--more--> <h2 id="the-what" style="position:relative;"><a href="#the-what" aria-label="the what permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>The what</h2> <p>The <code class="language-text">findIndex</code> method returns the index of the first element in an array if the callback method passed to it returns <code class="language-text">true</code>, otherwise it returns <code class="language-text">-1</code>.</p> <div class="gatsby-code-button-container" data-toaster-id="99984990542885930000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const isPerfectSquare = (num) => { return num > 0 && Math.sqrt(num) % 1 === 0; } console.log([1, 3, 8, 9, 12].findIndex(isPerfectSquare)); // 1 console.log([1, 6, 7, 10, 14].findIndex(isPerfectSquare)); // -1`, `99984990542885930000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">isPerfectSquare</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">num</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> num <span class="token operator">></span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> Math<span class="token punctuation">.</span><span class="token function">sqrt</span><span class="token punctuation">(</span>num<span class="token punctuation">)</span> <span class="token operator">%</span> <span class="token number">1</span> <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">12</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">findIndex</span><span class="token punctuation">(</span>isPerfectSquare<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 1</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">14</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">findIndex</span><span class="token punctuation">(</span>isPerfectSquare<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// -1</span></code></pre></div> <p>There are two facts you should know:</p> <ul> <li>This method does not run once it found the first matching element.</li> <li>It does not change the original array.</li> </ul> <h2 id="syntax" style="position:relative;"><a href="#syntax" aria-label="syntax permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Syntax</h2> <div class="gatsby-code-button-container" data-toaster-id="659264112255408800" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`array.findIndex(function(currentValue, index, arr), thisValue);`, `659264112255408800`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">array<span class="token punctuation">.</span><span class="token function">findIndex</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">currentValue<span class="token punctuation">,</span> index<span class="token punctuation">,</span> arr</span><span class="token punctuation">)</span><span class="token punctuation">,</span> thisValue<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div> <h3 id="parameters" style="position:relative;"><a href="#parameters" aria-label="parameters permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Parameters</h3> <ul> <li><strong>function:</strong> This is your callback function which checks for a condition to match the element you’re after.</li> <li><strong>currentValue:</strong> This holds the current element’s value.</li> <li><strong>index:</strong> This is an optional parameter which holds the current index.</li> <li><strong>arr:</strong> This is also an optional parameter which holds the array that the current element belongs to.</li> <li><strong>thisValue:</strong> Yet another optional parameter, if a value is passed, it will be used as <code class="language-text">this</code> value inside the function, otherwise <code class="language-text">undefined</code> will be passed.</li> </ul> <h3 id="return-value" style="position:relative;"><a href="#return-value" aria-label="return value permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Return value</h3> <p>It will return the index of the found item or <code class="language-text">-1</code> if the callback function is not satisfied.</p> <h2 id="how-it-works-under-the-hood" style="position:relative;"><a href="#how-it-works-under-the-hood" aria-label="how it works under the hood permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>How it works under the hood?</h2> <p>When the <code class="language-text">findIndex</code> is called with one or two arguments, the following steps are executed:</p> <ol> <li>Let <code class="language-text">O</code> be ? <code class="language-text">ToObject(this value)</code></li> <li>Let <code class="language-text">len</code> be ? <code class="language-text">LengthOfArrayLike(O)</code></li> <li>If <code class="language-text">IsCallback(predicate)</code> is <code class="language-text">false</code>, throw a <strong>TypeError</strong> exception</li> <li>Let <code class="language-text">k</code> be 0</li> <li>Repeat, while <code class="language-text">k &lt; len</code></li> <li>Let <code class="language-text">Pk</code> be ! <code class="language-text">ToString(k)</code></li> <li>Let <code class="language-text">kValue</code> be ? <code class="language-text">Get(O, Pk)</code></li> <li>Let <code class="language-text">testResult</code> be ! <code class="language-text">ToBoolean(? Call(predicate, thisArg, « kValue, k, O »))</code></li> <li>If <code class="language-text">testResult</code> is <code class="language-text">true</code>, return <code class="language-text">k</code></li> <li>Set <code class="language-text">k</code> to <code class="language-text">k + 1</code></li> <li>Return <code class="language-text">-1</code></li> </ol><![CDATA[Take a selfie 🤳 using Image Capture API and a few lines of code]]>https://yashints.dev/blog/2020/09/06/image-capture-apihttps://yashints.dev/blog/2020/09/06/image-capture-apiSun, 06 Sep 2020 00:00:00 GMT<p>It’s been a while since I last wrote about Intersection Observer V2, partly because I had a lot on my plate and I was feeling exhausted and partly because I was working on my first <a href="app.pluralsight.com/library/courses/web-performance-progressive-web-apps">PluralSight course on web performance for PWAs</a>.</p> <p>But I am back, and this time we’re going to review how to take a selfie from your webcam using <a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaStream_Image_Capture_API">Image Capture API</a>.</p> <!--more--> <h2 id="image-capture-api" style="position:relative;"><a href="#image-capture-api" aria-label="image capture api permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Image Capture API</h2> <p>There are some really useful APIs which allow us to work with media like audio, video, etc. I will write about those too, but this time I wanted to show you how you can extract a frame from your video feed such as your webcam with a few lines of code.</p> <p><a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaStream_Image_Capture_API">Image Capture API</a> enables us to capture an image or frame from video devices. In addition to capturing data, it also allows you to retrieve information about device capability such as image size, red-eye detection and whether or not there is flash turned on.</p> <h2 id="usage" style="position:relative;"><a href="#usage" aria-label="usage permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Usage</h2> <p>We need to take some actions to be able to work with media devices. First thing first we need to get a reference of the device:</p> <div class="gatsby-code-button-container" data-toaster-id="14508544077956320000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`navigator.mediaDevices.getUserMedia({ video: true }) .then(mediaStream => { // Do something with the stream. })`, `14508544077956320000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">navigator<span class="token punctuation">.</span>mediaDevices<span class="token punctuation">.</span><span class="token function">getUserMedia</span><span class="token punctuation">(</span><span class="token punctuation">{</span> video<span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">mediaStream</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// Do something with the stream.</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div> <p>Next we need to get the visual parts of the media stream by calling <code class="language-text">getVideoTracks</code> method of the <code class="language-text">mediaStream</code> object:</p> <div class="gatsby-code-button-container" data-toaster-id="74403293681219200000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const track = mediaStream.getVideoTracks()[0];`, `74403293681219200000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> track <span class="token operator">=</span> mediaStream<span class="token punctuation">.</span><span class="token function">getVideoTracks</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span></code></pre></div> <p>Of course we’re assuming that the first item in the array is the one you want to use, but don’t worry if not, you can loop through all the tracks, find the one you need and either get it with its right index, or by calling <code class="language-text">getTrackById</code> method.</p> <p>After we’ve got our track, it’s time to capture our image. If you wanted to configure some of the settings on your media device such as zoom level, you need to do it now before capturing our image:</p> <div class="gatsby-code-button-container" data-toaster-id="88107719975245970000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const capabilities = track.getCapabilities(); // Check whether zoom is supported or not. if(!capabilities.zoom) { return; } const zoom = capabilities.zoom.max - capabilities.zoom.min; track.applyConstraints({ advanced : [{ zoom: zoom }] });`, `88107719975245970000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> capabilities <span class="token operator">=</span> track<span class="token punctuation">.</span><span class="token function">getCapabilities</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Check whether zoom is supported or not.</span> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span>capabilities<span class="token punctuation">.</span>zoom<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> zoom <span class="token operator">=</span> capabilities<span class="token punctuation">.</span>zoom<span class="token punctuation">.</span>max <span class="token operator">-</span> capabilities<span class="token punctuation">.</span>zoom<span class="token punctuation">.</span>min<span class="token punctuation">;</span> track<span class="token punctuation">.</span><span class="token function">applyConstraints</span><span class="token punctuation">(</span><span class="token punctuation">{</span> advanced <span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> zoom<span class="token operator">:</span> zoom <span class="token punctuation">}</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div> <p>When we’re done with settings, we can then create an instance of the <code class="language-text">ImageCapture</code> object:</p> <div class="gatsby-code-button-container" data-toaster-id="34553912766531146000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`let imageCapture = new ImageCapture(track);`, `34553912766531146000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">let</span> imageCapture <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ImageCapture</span><span class="token punctuation">(</span>track<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div> <p>Once that’s done, you can capture an image from your video feed by calling the <code class="language-text">takePhoto</code> method:</p> <div class="gatsby-code-button-container" data-toaster-id="33032034442402103000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`imageCapture.takePhoto() .then(blob => createImageBitmap(blob)) .then(imageBitmap => { // do something with the photo }) .catch(error => console.error(error));`, `33032034442402103000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">imageCapture<span class="token punctuation">.</span><span class="token function">takePhoto</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">blob</span> <span class="token operator">=></span> <span class="token function">createImageBitmap</span><span class="token punctuation">(</span>blob<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">imageBitmap</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// do something with the photo</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token parameter">error</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>error<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div> <h2 id="permissions" style="position:relative;"><a href="#permissions" aria-label="permissions permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Permissions</h2> <p>Similar to other APIs you would need permission to be able to access the webcam on devices. If you didn’t see any pop up, make sure you give the camera permission to the site on your browser to be able to get your code working properly. You can try that with below demo.</p> <h2 id="demo" style="position:relative;"><a href="#demo" aria-label="demo permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Demo</h2> <p>You can see a working example of this in my CodePen below:</p> <iframe height="265" style="width: 100%;" scrolling="no" title="Image Capture API" src="https://codepen.io/yashints/embed/preview/bGpaWKY?height=265&theme-id=light&default-tab=result" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/yashints/pen/bGpaWKY'>Image Capture API</a> by Yaser Adel Mehraban (<a href='https://codepen.io/yashints'>@yashints</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> <p>I hope you’ve learnt a new thing or two and till next time 👋🏽.</p><![CDATA[Introducing the Intersection Observer V2 ⛌]]>https://yashints.dev/blog/2020/06/22/intersection-observer-v2https://yashints.dev/blog/2020/06/22/intersection-observer-v2Mon, 22 Jun 2020 00:00:00 GMT<p>As I mentioned in <a href="https://yashints.dev/blog/2018/11/12/web-perf-4">one of my other posts</a>, <strong>Intersection Observer</strong> will report when an element appears in the viewport, after applying all <code class="language-text">overflow</code> and <code class="language-text">CSS clips</code>. However, there is no way currently to find out whether an item is being put on top of this element, or some filter is applied to it which may alter or obscure the element’s display.</p> <!--more--> <h2 id="context" style="position:relative;"><a href="#context" aria-label="context permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Context</h2> <p><a href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API">Intersection Observer</a> is now widely used by developers especially since Safari added support a while back and it’s now available in all major browsers. If you want to be notified when an element appears in the viewport such as an image, if you want to lazy load it you can use this API. In its most basic form the code looks like this:</p> <div class="gatsby-code-button-container" data-toaster-id="64568849468052455000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const logIfIsInViewPort = (entries) => { for (const entry of entries) { if (entry.isIntersecting) { console.log(entry); } } }; const observer = new IntersectionObserver(logIfIsInViewPort); observer.observe(document.querySelector('.element-selector'));`, `64568849468052455000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">logIfIsInViewPort</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">entries</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> entry <span class="token keyword">of</span> entries<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>entry<span class="token punctuation">.</span>isIntersecting<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>entry<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">const</span> observer <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">IntersectionObserver</span><span class="token punctuation">(</span>logIfIsInViewPort<span class="token punctuation">)</span><span class="token punctuation">;</span> observer<span class="token punctuation">.</span><span class="token function">observe</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.element-selector'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div> <h2 id="the-problem" style="position:relative;"><a href="#the-problem" aria-label="the problem permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>The problem</h2> <p>As great as it sounds, this API is not perfect. For example it can’t tell you whether or not an element is covered by another content (which is called occluded), or if a filter is applied to it to hide or obscure it’s content (such as <code class="language-text">opacity</code>, <code class="language-text">filter</code>, <code class="language-text">transform</code>, etc.).</p> <p>This can lead to dangerous situations where some people might do fraud or abuse the web. So <a href="https://w3c.github.io/IntersectionObserver/v2/">Intersection Observer V2</a> was born to prevent these types of scenarios.</p> <h2 id="intersection-observer-v2" style="position:relative;"><a href="#intersection-observer-v2" aria-label="intersection observer v2 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Intersection Observer V2</h2> <p>As I said, the primary motivation for this API is to prevent those situations where a fraud might be possible, or people could abuse the user’s privacy in a way especially if the said content is put in an iframe.</p> <p>Intersection Observer V2 works by tracking the actual visibility of the element, just like the end user would see it. By passing an option to it’s constructor, the collection of <code class="language-text">IntersectionObserverEntry</code> will contain a new boolean called <code class="language-text">isVisible</code>.</p> <div class="gatsby-code-button-container" data-toaster-id="19911711324704506000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const handler = (changes) => { for(const change in changes) { // feature detection if(typeof change.isVisible !== 'undefined') { if(change.isIntersecting && change.isVisible) { console.log(\`Visible since \${change.time}\`); } else { // fallback to v1 if not supported change.isVisible = true; } } } } const observer = new IntersectionObserver(handler, { threshold: [1.0], trackVisibility: true, // this will give you the isVisible property delay: 100 }); observer.observe(document.querySelector('.target-element-selector'));`, `19911711324704506000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">handler</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">changes</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">const</span> change <span class="token keyword">in</span> changes<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// feature detection</span> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token keyword">typeof</span> change<span class="token punctuation">.</span>isVisible <span class="token operator">!==</span> <span class="token string">'undefined'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span><span class="token punctuation">(</span>change<span class="token punctuation">.</span>isIntersecting <span class="token operator">&amp;&amp;</span> change<span class="token punctuation">.</span>isVisible<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Visible since </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>change<span class="token punctuation">.</span>time<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token comment">// fallback to v1 if not supported</span> change<span class="token punctuation">.</span>isVisible <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> observer <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">IntersectionObserver</span><span class="token punctuation">(</span>handler<span class="token punctuation">,</span> <span class="token punctuation">{</span> threshold<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">1.0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> trackVisibility<span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token comment">// this will give you the isVisible property</span> delay<span class="token operator">:</span> <span class="token number">100</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> observer<span class="token punctuation">.</span><span class="token function">observe</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.target-element-selector'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div> <h2 id="additional-parameters" style="position:relative;"><a href="#additional-parameters" aria-label="additional parameters permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Additional parameters</h2> <p>The object which is passed in the constructor has a few properties:</p> <ul> <li><strong>threshold</strong>: A list of thresholds which will trigger a callback.</li> <li><strong>trackVisibility</strong>: A boolean indicating whether or not to track the visibility of the element.</li> <li><strong>delay</strong>: A number defining the minimum delay in milliseconds between notification for a given object.</li> </ul> <blockquote> <p>💡 Note that tracking visibility is an expensive operation and should only be used when necessary. The performance implications can cause more harm than good if abused.</p> </blockquote> <h2 id="how-does-it-determine-visibility" style="position:relative;"><a href="#how-does-it-determine-visibility" aria-label="how does it determine visibility permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>How does it determine visibility?</h2> <p>Determining whether the element is visible or not is not as simple as you might think. Based on the spec:</p> <ul> <li>If <code class="language-text">false</code> is passed as the value of <code class="language-text">trackVisibility</code>, the element is considered visible.</li> <li>If the target element has an effective transformation matrix other than <code class="language-text">2D</code> then the element is considered invisible.</li> <li>If the target element or any of its children, has an effective capacity other than <code class="language-text">1.0</code>, then it’s considered invisible.</li> <li>If the target element or any of its children has a filter applied, then it’s considered invisible.</li> <li>If the browser cannot guarantee the target is fully visible, then it’s considered invisible.</li> </ul> <h2 id="whats-the-catch" style="position:relative;"><a href="#whats-the-catch" aria-label="whats the catch permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>What’s the catch?</h2> <p>This is in a draft state and still work in progress. Apart from Chrome, none of the other major browsers currently support it.</p> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>Although this hasn’t been implemented in most browsers yet, it’s a great tool to prevent some of the common attacks such as <code class="language-text">clickjacking</code> or <code class="language-text">likejacking</code>, or <code class="language-text">cursorjacking</code>.</p><![CDATA[Chrome - where did save sessions go? 🤔]]>https://yashints.dev/blog/2020/06/17/chrome-save-tabshttps://yashints.dev/blog/2020/06/17/chrome-save-tabsWed, 17 Jun 2020 00:00:00 GMT<p>I remember a while back (not sure how long), Chrome had the ability to save all tabs when you closed the browser regardless of whether it was by accident or not. But they removed that ability and now if you close the window you will lose the tabs.</p> <!--more--> <h2 id="what-now" style="position:relative;"><a href="#what-now" aria-label="what now permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>What now?</h2> <p>Well there are still some ways you can save your current tabs and open them next time you open a new Chrome window.</p> <h2 id="1-small-hack-but-works-most-times-" style="position:relative;"><a href="#1-small-hack-but-works-most-times-" aria-label="1 small hack but works most times permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>1. Small hack but works (most times 😁)</h2> <p>Open your task manager and kill the Chrome’s task. It’s a dirty hack but it works. When you open Chrome next time it asks you do you want to restore the last session and when you click the button, it will open all of your previously open tabs.</p> <p>So first kill the task:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 713px; " > <a class="gatsby-resp-image-link" href="/static/00050809776c4281b92e142067ba9f3c/def00/kill-chrome.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 97.77777777777777%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAAAAECAwX/xAAWAQEBAQAAAAAAAAAAAAAAAAACAAH/2gAMAwEAAhADEAAAAetN4Qq3VWArQW//xAAaEAACAgMAAAAAAAAAAAAAAAACEwABEBIg/9oACAEBAAEFAkhFBEhja+f/xAAYEQADAQEAAAAAAAAAAAAAAAACElEAEP/aAAgBAwEBPwFRmUZ3/8QAGREAAQUAAAAAAAAAAAAAAAAAAQAQERJR/9oACAECAQE/AZKsdf8A/8QAGBAAAwEBAAAAAAAAAAAAAAAAAAExMiD/2gAIAQEABj8CiMoyi9f/xAAZEAEAAwEBAAAAAAAAAAAAAAABABExECH/2gAIAQEAAT8hPB7QJcFlUwGt4bDJ/9oADAMBAAIAAwAAABAEEHz/xAAYEQADAQEAAAAAAAAAAAAAAAAAAWGREP/aAAgBAwEBPxCDCTELn//EABYRAAMAAAAAAAAAAAAAAAAAACBhof/aAAgBAgEBPxB9Bf/EAB8QAQACAgICAwAAAAAAAAAAAAEAESExUdFBcaGx8P/aAAgBAQABPxBhYKZu+4lv5e5+B7jI0sV4OI9q68aiQ3LOCBg9H1Nk0ep//9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Kill Chrome task in windows task manager" title="Kill Chrome task in windows task manager" src="/static/00050809776c4281b92e142067ba9f3c/def00/kill-chrome.jpg" srcset="/static/00050809776c4281b92e142067ba9f3c/6f81f/kill-chrome.jpg 270w, /static/00050809776c4281b92e142067ba9f3c/09d21/kill-chrome.jpg 540w, /static/00050809776c4281b92e142067ba9f3c/def00/kill-chrome.jpg 713w" sizes="(max-width: 713px) 100vw, 713px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <p>Later when you open a new window:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 324px; " > <a class="gatsby-resp-image-link" href="/static/84095ac3a013789fa76de2ca2790f717/033fb/restore.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 51.11111111111111%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAECBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHdVyiJK//EABoQAQACAwEAAAAAAAAAAAAAAAEAAhARITL/2gAIAQEAAQUCnIacW80AP//EABURAQEAAAAAAAAAAAAAAAAAAAAB/9oACAEDAQE/AUr/xAAWEQEBAQAAAAAAAAAAAAAAAAABABH/2gAIAQIBAT8BJMv/xAAZEAACAwEAAAAAAAAAAAAAAAAAARARITH/2gAIAQEABj8CLZjnh//EABsQAQACAgMAAAAAAAAAAAAAAAEAIRFBEFFx/9oACAEBAAE/Ib6iDRvKzCoT3gChMkoIL0T/2gAMAwEAAgADAAAAEP8A7//EABYRAQEBAAAAAAAAAAAAAAAAAAERAP/aAAgBAwEBPxBYXULv/8QAFhEBAQEAAAAAAAAAAAAAAAAAEQAB/9oACAECAQE/EMOkgv/EABkQAQEBAQEBAAAAAAAAAAAAAAERACExof/aAAgBAQABPxBvkJqVANcB93YMcpWPMapDolHOAppAN//Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Restore sessions in Chrome" title="Restore sessions in Chrome" src="/static/84095ac3a013789fa76de2ca2790f717/033fb/restore.jpg" srcset="/static/84095ac3a013789fa76de2ca2790f717/6f81f/restore.jpg 270w, /static/84095ac3a013789fa76de2ca2790f717/033fb/restore.jpg 324w" sizes="(max-width: 324px) 100vw, 324px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <h2 id="2-save-them-as-bookmarks" style="position:relative;"><a href="#2-save-them-as-bookmarks" aria-label="2 save them as bookmarks permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>2. Save them as bookmarks</h2> <p>Yes, you read right. You can save all open tabs as bookmarks and open them all later when you come back. Simply press <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>d</kbd> in windows or <kbd>⌘</kbd> + <kbd>Shift</kbd> + <kbd>d</kbd> in Mac to save all your open tabs in a new bookmark folder.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 454px; " > <a class="gatsby-resp-image-link" href="/static/7c97dd161117ff703d6b13bc8cd4c85b/835f3/bookmarkall.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 117.77777777777779%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAYABQDASIAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAAAAECAwX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAv/aAAwDAQACEAMQAAAB7eiSAKFTcTX/xAAYEAEAAwEAAAAAAAAAAAAAAAABAAIgQv/aAAgBAQABBQLrTcGf/8QAFhEBAQEAAAAAAAAAAAAAAAAAARAR/9oACAEDAQE/AYuT/8QAFxEAAwEAAAAAAAAAAAAAAAAAAQIQEf/aAAgBAgEBPwGKNn//xAAWEAEBAQAAAAAAAAAAAAAAAAARECD/2gAIAQEABj8CNk//xAAaEAACAgMAAAAAAAAAAAAAAAABERAhIGGR/9oACAEBAAE/IXS3KzBTbOo//9oADAMBAAIAAwAAABCgwHz/xAAWEQEBAQAAAAAAAAAAAAAAAAABEBH/2gAIAQMBAT8QjDSf/8QAFhEBAQEAAAAAAAAAAAAAAAAAARAR/9oACAECAQE/EIKxn//EAB0QAQACAgIDAAAAAAAAAAAAAAEAESExQXEQYZH/2gAIAQEAAT8QWVqIt2friV1K6ho8MHiMzjVTTPsKm5//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Chrome bookmark all open tabs" title="Chrome bookmark all open tabs" src="/static/7c97dd161117ff703d6b13bc8cd4c85b/835f3/bookmarkall.jpg" srcset="/static/7c97dd161117ff703d6b13bc8cd4c85b/6f81f/bookmarkall.jpg 270w, /static/7c97dd161117ff703d6b13bc8cd4c85b/835f3/bookmarkall.jpg 454w" sizes="(max-width: 454px) 100vw, 454px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <p>Later on when you come back and open a new window, you can right click on the folder you created previously and select open all tabs:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 716px; " > <a class="gatsby-resp-image-link" href="/static/5ae22876b352406786c6a2512308e1c4/d80c4/open-all-bookmarks.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 103.7037037037037%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAVABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAe9INAgNA//EABkQAAIDAQAAAAAAAAAAAAAAAAABAhARQf/aAAgBAQABBQK8FHHXT//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQMBAT8BH//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BH//EABYQAQEBAAAAAAAAAAAAAAAAAAEgIf/aAAgBAQAGPwKHWf/EAB0QAAICAQUAAAAAAAAAAAAAAAABESFBEDFRYfD/2gAIAQEAAT8hoy6ZPTPbJgrOXOi3wNwEf//aAAwDAQACAAMAAAAQo888/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPxAf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPxAf/8QAIRABAAIABAcAAAAAAAAAAAAAAQARITFRkUFhcYGh0fD/2gAIAQEAAT8QtXd4QeJH3OCCjxe5YWl3SyDe0cHQcu0L1dpjQmyUAaTJP//Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Chrome open all pages in bookmark folder" title="Chrome open all pages in bookmark folder" src="/static/5ae22876b352406786c6a2512308e1c4/d80c4/open-all-bookmarks.jpg" srcset="/static/5ae22876b352406786c6a2512308e1c4/6f81f/open-all-bookmarks.jpg 270w, /static/5ae22876b352406786c6a2512308e1c4/09d21/open-all-bookmarks.jpg 540w, /static/5ae22876b352406786c6a2512308e1c4/d80c4/open-all-bookmarks.jpg 716w" sizes="(max-width: 716px) 100vw, 716px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <blockquote> <p>⚠️ This technique won’t help you if your browser crashes for some reason.</p> </blockquote> <h2 id="3-i-am-too-tired-to-do-all-of-that" style="position:relative;"><a href="#3-i-am-too-tired-to-do-all-of-that" aria-label="3 i am too tired to do all of that permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>3. I am too tired to do all of that</h2> <p>If you don’t want to open your task manager, or don’t want to use bookmarks, don’t worry. There are some extensions which can help you with that.</p> <h3 id="tab-session-manager" style="position:relative;"><a href="#tab-session-manager" aria-label="tab session manager permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Tab Session Manager</h3> <p><a href="https://chrome.google.com/webstore/detail/tab-session-manager/iaiomicjabeggjcfkbimgmglanimpnae?hl=en">Tab Session Manager</a> is a Chrome extension which allows you to do:</p> <ul> <li>Save and restore windows and tabs</li> <li>Manage sessions with name and tags</li> <li>Auto save when window is closed</li> <li>Auto save at regular intervals</li> <li>Import and export sessions</li> <li>Compatibility with Firefox extension</li> <li>Cloud sync</li> </ul> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 640px; " > <a class="gatsby-resp-image-link" href="/static/b0bc166de7ab6fbf44731de9cd404bd4/c08c5/tabmanager.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 62.5925925925926%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAECBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHbViIoX//EABYQAAMAAAAAAAAAAAAAAAAAABARIP/aAAgBAQABBQKEP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABUQAQEAAAAAAAAAAAAAAAAAACAx/9oACAEBAAY/Aov/xAAaEAACAwEBAAAAAAAAAAAAAAAAAREhMRBB/9oACAEBAAE/IXtSJXqElGD0g7fP/9oADAMBAAIAAwAAABDHD//EABURAQEAAAAAAAAAAAAAAAAAABAR/9oACAEDAQE/EIf/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAbEAADAQADAQAAAAAAAAAAAAABESEAMUFRcf/aAAgBAQABPxCVKCcWUUX4Bxi2p24CXBImnAWvclB1v//Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Chrome Tab Session Manager extension" title="Chrome Tab Session Manager extension" src="/static/b0bc166de7ab6fbf44731de9cd404bd4/c08c5/tabmanager.jpg" srcset="/static/b0bc166de7ab6fbf44731de9cd404bd4/6f81f/tabmanager.jpg 270w, /static/b0bc166de7ab6fbf44731de9cd404bd4/09d21/tabmanager.jpg 540w, /static/b0bc166de7ab6fbf44731de9cd404bd4/c08c5/tabmanager.jpg 640w" sizes="(max-width: 640px) 100vw, 640px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <p>It also has <a href="https://microsoftedge.microsoft.com/addons/detail/jkjjclfiflhpjangefhgfjhgfbhajadk">Microsoft</a> Edge and <a href="https://addons.mozilla.org/ja/firefox/addon/tab-session-manager/">Firefox</a> versions which is great.</p> <h3 id="session-buddy" style="position:relative;"><a href="#session-buddy" aria-label="session buddy permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Session Buddy</h3> <p><a href="https://chrome.google.com/webstore/detail/session-buddy/edacconmaakjimmfgnblocblbcdcpbko?hl=en">Session Buddy</a> is a popular extension with more than 24K installs. It will do all of the above for you automatically in one place. Whether your browser crashes or you choose to close it manually.</p> <p><a href="https://www.youtube.com/watch?v=wY4NKrD1DWQ"><img src="https://img.youtube.com/vi/wY4NKrD1DWQ/0.jpg" alt="IMAGE ALT TEXT HERE"></a></p> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>Hope this helps you from a possible disaster if you have millions of tabs open at a time. If you are a tab person, check out my other article on <a href="https://dev.to/yashints/chrome-arrange-your-tabs-with-tab-groups-267f">managing your tabs in Chrome here</a>. Until next time, 👋🏽.</p><![CDATA[Chrome - Arrange your tabs with tab groups 😍]]>https://yashints.dev/blog/2020/06/15/chrome-tab-groupshttps://yashints.dev/blog/2020/06/15/chrome-tab-groupsMon, 15 Jun 2020 00:00:00 GMT<p>If you’re one of those people with so many tabs open than you can manage, read on.</p> <!--more--> <h2 id="the-why" style="position:relative;"><a href="#the-why" aria-label="the why permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>The why</h2> <p>For those of you who have many tabs open all at the same time and are struggling to keep a tab on your tabs, the time has come to get a bit more organised using this new feature in Chrome called tab groups.</p> <p>The whole purpose has been to help users keep their tabs organised and easier to find them in their sea of open tabs.</p> <h2 id="how-can-i-do-it" style="position:relative;"><a href="#how-can-i-do-it" aria-label="how can i do it permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>How can I do it?</h2> <p>Simply right click your tab and select <strong>Add tab to tab group</strong> option. Then there will be a dot right before your tab. Click on the dot, a pop up will open in which you can select a colour for your tab group, and name your group.</p> <p>If you are clicking on an existing group, you will have the following options in addition:</p> <ul> <li>Add a new tab to the group</li> <li>Ungroup tabs in a group</li> <li>Close group</li> <li>Move the group to a new window</li> <li>Send feedback if you have any</li> </ul> <p>I’ve demonstrated this in below video:</p> <p><img src="/3d90142e4896a499fa70ca6655e929ff/chrome-tabs.gif" alt="Adding tabs to tab groups in Chrome"></p> <h2 id="but-i-dont-see-the-option" style="position:relative;"><a href="#but-i-dont-see-the-option" aria-label="but i dont see the option permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>But I don’t see the option</h2> <p>If you can’t see the option, don’t worry, just go to <code class="language-text">chrome://flags</code>, then search for <code class="language-text">tab groups</code> and enable the option. It’s still experimental, but you can use it now.</p> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>Hope this will help you to keep a tab on your tabs and till next time 👋🏽.</p><![CDATA[Did you know about scroll to text? 📜]]>https://yashints.dev/blog/2020/06/14/scroll-to-texthttps://yashints.dev/blog/2020/06/14/scroll-to-textSun, 14 Jun 2020 00:00:00 GMT<p>You probably have used fragments in links to point a link to a part of your page such as a heading. This technique is used in table of content for example and it’s a common pattern.</p> <!--more--> <h2 id="background" style="position:relative;"><a href="#background" aria-label="background permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Background</h2> <p>To extend the current support for scrolling to an anchor element in a page, the W3C have proposed a solution which basically adds the ability to link to a DOM element with id, or textual content on a page to make it easier for browsers to understand what the users are interested and scroll there when they visit the page. In addition to make it visually easier to follow, they have added the highlight to the text so that users will know where to look at on first sight.</p> <h2 id="scroll-to-text-fragment" style="position:relative;"><a href="#scroll-to-text-fragment" aria-label="scroll to text fragment permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Scroll to Text Fragment</h2> <p>So that’s how <a href="https://github.com/WICG/scroll-to-text-fragment">Scroll to Text Fragment</a> was born. It has been shipped to Chrome and Microsoft Edge called <a href="https://github.com/WICG/scroll-to-text-fragment">Scroll to Text Fragment</a> which allows you to link to a specific text on a page, using a fragment provided in the URL. When the page is loaded, the browser highlights the text and scrolls it into view.</p> <p>This is the generic syntax:</p> <div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">#:~:text=[prefix-,]textStart[,textEnd][,-suffix] context |-------match-----| context</code></pre></div> <blockquote> <p>💡 Square brackets indicate an optional parameter.</p> </blockquote> <p>Here is an example:</p> <div class="gatsby-code-button-container" data-toaster-id="13778192983060445000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<a href=&quot;https://yashints.dev/#:~:text=Meet&text=Yas&quot;> Click to go to a specific portion of a page </a>`, `13778192983060445000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://yashints.dev/#:~:text=Meet&amp;text=Yas<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Click to go to a specific portion of a page <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span></code></pre></div> <p>And you can test it live by <a href="https://yashints.dev#:~:text=Meet&#x26;text=Yas">clicking here</a>.</p> <p>If you want to target an exact text:</p> <div class="gatsby-code-button-container" data-toaster-id="14326418505777783000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<a href=&quot;https://yashints.dev/#:~:text=almond%20croissant%20addict&quot;> Click to go to a specific portion of a page </a>`, `14326418505777783000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://yashints.dev/#:~:text=almond%20croissant%20addict<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Click to go to a specific portion of a page <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span></code></pre></div> <p><a href="https://yashints.dev/#:~:text=almond%20croissant%20addict">Try it here</a>.</p> <p>You can also add an end text in which case the text directive refers to a range of text on the page.</p> <div class="gatsby-code-button-container" data-toaster-id="5355202373419932000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<a href=&quot;https://yashints.dev/#:~:text=Although,web%20developer&quot;> Click to go to a specific portion of a page </a>`, `5355202373419932000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://yashints.dev/#:~:text=Although,web%20developer<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Click to go to a specific portion of a page <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span></code></pre></div> <p><a href="https://yashints.dev/#:~:text=Although,web%20developer">Try it here</a>.</p> <h2 id="use-cases" style="position:relative;"><a href="#use-cases" aria-label="use cases permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Use cases</h2> <h3 id="search-engines" style="position:relative;"><a href="#search-engines" aria-label="search engines permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Search engines</h3> <p>When search engines will link to pages which contain relevant information to the query, they will scroll and highlight that so the user will find it easier.</p> <h3 id="citation--reference-links" style="position:relative;"><a href="#citation--reference-links" aria-label="citation reference links permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Citation / Reference links</h3> <p>Links are sometimes used as citations on some pages where the author wishes to enforce a claim by pointing to a reference such as <em>Wikipedia</em>. These reference pages can contains large chunks of text and finding the information can be difficult. So having the ability to scroll to that section and highlight it is really encouraging to readers to follow the links.</p> <h3 id="sharing-a-specific-text-or-paragraph" style="position:relative;"><a href="#sharing-a-specific-text-or-paragraph" aria-label="sharing a specific text or paragraph permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Sharing a specific text or paragraph</h3> <p>Sometimes you want to share a piece of text to someone for example by email or on social media, it’s really helpful to be able to link directly to the specific section rather than the whole page.</p> <p>Nowadays people share short snippets directly in tweets or create screenshots which can contain more text and post those. With this they won’t need to do that since links can be more meaningful.</p> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>And that’s how the web is moving towards a better place where users are the centre of attention for us developers and the more we know how to make their lives easier the more they trust us to take care of it for them.</p> <p>Enjoy your evening and till next time 👋🏽.</p><![CDATA[Links and JavaScript 🔗]]>https://yashints.dev/blog/2020/06/03/linkshttps://yashints.dev/blog/2020/06/03/linksWed, 03 Jun 2020 00:00:00 GMT<p>I see some occasions where web developers who are a bit less familiar with accessibility use links incorrectly in different forms. So I thought let’s write a quick guide on <em>Links</em> in JavaScript apps.</p> <!--more--> <h2 id="background" style="position:relative;"><a href="#background" aria-label="background permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Background</h2> <p>It’s safe to assume that anyone who’s used the web have seen them. They take users from one page to another either within the same application or to an external website. There were really hot when they were introduced back in <strong>1966</strong> by a team led by <a href="https://en.wikipedia.org/wiki/Douglas_Engelbart">Douglas Engelbart</a>. </p> <p>In the early 1980s <em>Ben Shneiderman</em>, a computer scientist at the University of Maryland, with his graduate student <em>Dan Ostroff</em> were preparing a videodisk exhibit for a museum. It was then where they used a caption that had all the information and users could click on it to see the photo associated with it.</p> <p>At first, this discovery was called <code class="language-text">embedded menu</code> but that term was quickly replaced by <code class="language-text">hyperlink</code>. <a href="https://en.wikipedia.org/wiki/Tim_Berners-Lee">Tim Berners-Lee</a> cited Shneiderman’s hyperlink work in his spring 1989 manifesto for what would become the World Wide Web.</p> <p>Back then, this feature was super hot and it still is. People use it without even thinking about it and it’s become a natural part of the web.</p> <h2 id="enough-background-tell-me-whats-this-all-about" style="position:relative;"><a href="#enough-background-tell-me-whats-this-all-about" aria-label="enough background tell me whats this all about permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Enough background, tell me what’s this all about</h2> <p>Let’s review what they do:</p> <ul> <li>As mentioned before they allow users to navigate between pages within a site or to an external one.</li> <li>And more importantly they help search engines and bots to find resources and going from one page to another by following the links. Think of this as a giant maze where they need to blindly follow the links to discover stuff.</li> <li>And last, the crawlers use them to understand the architecture of a site and the type of content they have. It’s a critical part of their decision making when assigning a page to a specific topic.</li> </ul> <h2 id="but-how-do-you-make-a-link" style="position:relative;"><a href="#but-how-do-you-make-a-link" aria-label="but how do you make a link permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>But how do you make a link?</h2> <h3 id="code-classlanguage-textacode-tag-with-code-classlanguage-texthrefcode" style="position:relative;"><a href="#code-classlanguage-textacode-tag-with-code-classlanguage-texthrefcode" aria-label="code classlanguage textacode tag with code classlanguage texthrefcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">a</code> tag with <code class="language-text">href</code></h3> <p>Turns out it’s not as straightforward as one might think. The simplest way to put a link on your site is to use a good old <code class="language-text">&lt;a&gt;</code> tag with a <code class="language-text">URL</code> which it points to in the <code class="language-text">href</code> attribute.</p> <div class="gatsby-code-button-container" data-toaster-id="77419175433140630000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<a href=&quot;/elsewhere&quot;>A good link, YES ╰(*°▽°*)╯</a>`, `77419175433140630000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/elsewhere<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>A good link, YES ╰(*°▽°*)╯<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span></code></pre></div> <h3 id="code-classlanguage-textacode-tag-with-code-classlanguage-texthrefcode-and-event-handler" style="position:relative;"><a href="#code-classlanguage-textacode-tag-with-code-classlanguage-texthrefcode-and-event-handler" aria-label="code classlanguage textacode tag with code classlanguage texthrefcode and event handler permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">a</code> tag with <code class="language-text">href</code> and event handler</h3> <p>For those with special circumstances, they might sprinkle a little bit of JavaScript on top and use an event handler to navigate the user programmatically:</p> <div class="gatsby-code-button-container" data-toaster-id="78397084257032600000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<a href=&quot;/elsewhere&quot; onclick=&quot;goTo('elsewhere')&quot;>Okay ¯\_(ツ)_/¯</a>`, `78397084257032600000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/elsewhere<span class="token punctuation">"</span></span> <span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>goTo(<span class="token punctuation">'</span>elsewhere<span class="token punctuation">'</span>)<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Okay ¯\_(ツ)_/¯<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span></code></pre></div> <p>This is fine as the link stays functional and you can upgrade the functionality using JavaScript. </p> <h3 id="code-classlanguage-textacode-tag-without-code-classlanguage-texthrefcode" style="position:relative;"><a href="#code-classlanguage-textacode-tag-without-code-classlanguage-texthrefcode" aria-label="code classlanguage textacode tag without code classlanguage texthrefcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">a</code> tag without <code class="language-text">href</code></h3> <p>But some people decide to remove the <code class="language-text">href</code> attribute. This is not a good idea because you now prevented crawlers to find out where this link goes to:</p> <div class="gatsby-code-button-container" data-toaster-id="42815276057756150000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<a onclick=&quot;goTo('elsewhere')&quot;>Please don't ╯︿╰</a>`, `42815276057756150000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>goTo(<span class="token punctuation">'</span>elsewhere<span class="token punctuation">'</span>)<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Please don't ╯︿╰<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span></code></pre></div> <h3 id="code-classlanguage-textacode-tag-with-code-classlanguage-texthrefcode-but-no-link" style="position:relative;"><a href="#code-classlanguage-textacode-tag-with-code-classlanguage-texthrefcode-but-no-link" aria-label="code classlanguage textacode tag with code classlanguage texthrefcode but no link permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">a</code> tag with <code class="language-text">href</code> but no link</h3> <p>In other occasions, people use the <code class="language-text">href</code> attribute without a URL or with a pseudo URL:</p> <div class="gatsby-code-button-container" data-toaster-id="53526990625834990000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<a href=&quot;javascript:goTo('elsewhere')&quot;>Seriously? (⊙_⊙)?</a>`, `53526990625834990000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>javascript:goTo(<span class="token punctuation">'</span>elsewhere<span class="token punctuation">'</span>)<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Seriously? (⊙_⊙)?<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span></code></pre></div> <p>This is even worse than the previous case as it just confuses the hell out of every crawler out there.</p> <h3 id="using-code-classlanguage-textbuttoncode" style="position:relative;"><a href="#using-code-classlanguage-textbuttoncode" aria-label="using code classlanguage textbuttoncode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>using <code class="language-text">button</code></h3> <p>You might think it’s a good idea to use a button to navigate the user, but let me tell you, that’s not a good idea either. The rule of thumb is that if the purpose is to do something on the current page, it could be a button. But if it’s takes users to another page or to an external site, it should be a link.</p> <div class="gatsby-code-button-container" data-toaster-id="82390907033244960000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<button onclick=&quot;goTo('elsewhere')&quot;>But why? <( _ _ )> </button>`, `82390907033244960000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>goTo(<span class="token punctuation">'</span>elsewhere<span class="token punctuation">'</span>)<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>But why? <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>(</span> <span class="token attr-name">_</span> <span class="token attr-name">_</span> <span class="token attr-name">)</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span></code></pre></div> <h3 id="any-other-html-element" style="position:relative;"><a href="#any-other-html-element" aria-label="any other html element permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>any other HTML element</h3> <p>It’s worth noting that you shouldn’t simulate a link using any other HTML element and add a click handler with JavaScript:</p> <div class="gatsby-code-button-container" data-toaster-id="54388084827722790000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<div onclick=&quot;goTo('elsewhere')&quot;>NOOOOOOOOOOOOOOOO!!!!!!!!!!!! (#\`O′)</div>`, `54388084827722790000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>goTo(<span class="token punctuation">'</span>elsewhere<span class="token punctuation">'</span>)<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>NOOOOOOOOOOOOOOOO!!!!!!!!!!!! (#`O′)<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code></pre></div> <p>This not only wrong for crawlers, but also messes up the screen readers and causes a lot of trouble for people with any vision impairment. So please just use a link with a proper URL.</p> <h2 id="what-is-a-proper-url-i-hear-you-ask" style="position:relative;"><a href="#what-is-a-proper-url-i-hear-you-ask" aria-label="what is a proper url i hear you ask permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>What is a proper URL? I hear you ask</h2> <p>You saw we ruled out the pseudo URLs like <code class="language-text">javascript:doSomething()</code>, but let’s take a look at URLs more closely. </p> <div class="gatsby-code-button-container" data-toaster-id="33297951213962260000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`http://example.com/old-school-url example.com/page#section`, `33297951213962260000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">http://example.com/old-school-url example.com/page#section</code></pre></div> <p>A URL contains these elements:</p> <ul> <li>A protocol (optional), which defines the protocol to be used for navigation such as <code class="language-text">http</code>, or <code class="language-text">https</code>.</li> <li>It also has a host, <code class="language-text">example.com</code> or <code class="language-text">yashints.dev</code>. A host is a name that one or some computers respond to. Usually it points to an IP address.</li> <li>It has a path to specific asset on that computer such as an HTML file, an image, CSS file or a font. But that’s not always the case, sometimes the path is handled via JavaScript and is used to replace part of the content in a page. This technique is called Single Page Application or SPA.</li> <li>Some URLs might contain another part such the second example above. That part which comes after the <code class="language-text">#</code> sign, is called a fragment identifier. By itself a fragment identifier is not a piece of content. It just points to a specific part in the content such as a header.</li> </ul> <blockquote> <p>💡 Because fragments are not suppose to point to different content, crawlers ignore them altogether. This means for single page applications where they use fragment like routing, crawlers don’t follow them and that’s why people use techniques such as server side rendering or SSR to allow crawlers become aware of the page’s content.</p> </blockquote> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>To sum it all up:</p> <ul> <li>Use proper link markup, <code class="language-text">a</code> tag with <code class="language-text">href</code> attribute.</li> <li>Do not use other HTML elements to navigate users.</li> <li>Do not omit the <code class="language-text">href</code> attribute on an anchor tag.</li> <li>And last but not least, do not use fragment identifiers to load different content in SPAs if you can.</li> </ul> <p>Hope you’ve enjoyed reading this and thanks for drooping by. Until next article, Ta.</p><![CDATA[Microsoft Build 2020 highlights 🔣]]>https://yashints.dev/blog/2020/05/23/build2020https://yashints.dev/blog/2020/05/23/build2020Sat, 23 May 2020 00:00:00 GMT<p><a href="https://mybuild.microsoft.com/">Microsoft Build</a> went on fully online and it came with some really exciting announcements. For us developers some of these can bring massive efficiencies. So let’s see what’s on offer.</p> <!--more--> <h2 id="wsl2" style="position:relative;"><a href="#wsl2" aria-label="wsl2 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>WSL2</h2> <p><a href="https://docs.microsoft.com/en-us/windows/wsl/">Windows Subsystem for Linux v2 (aka WSL2)</a> is here with a ton of awesome features allowing developers to have a really great experience working in a side by side Windows/Linux environment.</p> <ul> <li>No Hyper-V image is needed to run docker containers</li> <li>GPU Support</li> <li>100% system call compatibility</li> <li>Increased I/O performance</li> </ul> <h2 id="linux-gui-apps-in-windows" style="position:relative;"><a href="#linux-gui-apps-in-windows" aria-label="linux gui apps in windows permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Linux GUI apps in Windows</h2> <p>This was really an exciting announcements. Microsoft is adding a full Linux Kernel to its <a href="https://docs.microsoft.com/en-us/windows/wsl/">Windows Subsystem for Linux v2 (aka WSL2)</a> with GUI support and GPU acceleration.</p> <p>This will be enabled without us having to use X11 forwarding and it’s mainly designed for developers to run Linux integrated development environments alongside regular Windows apps.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1080px; " > <a class="gatsby-resp-image-link" href="/static/65b15eb608f5c4b3c8e1f45c40411cb3/29114/WSLGUIAppsNoName.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 56.29629629629629%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAABnWAAAZ1gEY0crtAAACnUlEQVQoz32QS2xMURjHr0iVLlCqNiwI8YjHxqLxSIjB0IiFhIqlncSCrYSkQQiRlsRKJA0RoTSq+hqaKq1SWq+m02H6mGnnPe2dO+193/tzZirxWDjJLznnS77f9z+fJD3QyFHwQGXO/SkK7ioU1mSZVzNF0W2FolsyRdeTzL0YZf7ZAMVnetlS+Y29lwSVX9l37jMrTnRQXPGCRYebkaSHOgW1Go/6Y3wajdPUG6Dp4yBvgwk6AxE6B8d42Reg8b0fX98wvf4RBoZCBEZGGQqNE4ol6B8K4w9H8X0YEcJak8I6g57gOGYmjW1aTKZTdHd1oaajyGN+lFiQiViIeEZDTkWJRsaRZZmMwNB1cBxwbYJhWQjrhLDepCecIpvJoKTDZAXxZBpNUwU6k/EQyUSEqGIRT4whKzKmGOw4LpZtoxumEDoMjuaETy0KGwy+xBVs3SAV8ZNJDqPpJqo6jSpqikiaTiWIyDqaOjPENE0Mw8ij51LiMjQ+JYTPhLDRoi+WwTFUBoJhfoxEcF0XXaQwBLYL06YjhGq+UTz/Ou6vQnAsK4QNDoXNNoNJBbQs5nQW9JlGsAXODI5FTOww1+3+Q+7rfwgtZjea7O+a5si7KSo+6BwTHO1WqRC1io4sx9sVyhsmqPmUyg8xLBvb/o1p2fkA30MZIWwBqVXQ/IsmwXPBUxfpkY10T0e6I3ZzdZILPRr/O5G0hVR8s5PF1e0sudFOSVVbnoVVr1hQ/ZrSKlG/9oalVzqZdbqeE7ca8fl81D73USd40tDK42e5extP6lu4fb8JaZvHy6EDXg7u9+L17Ma7x8OGbbtYudXDpp0eyk+eZ++pyyzfuIVlm7dTur6M0nVlLFlTRslqwaqtLF27k9JVO1i+fjc/AeeKxcal4rtbAAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Linux GUI in Windows Subsystem for Linux" title="Linux GUI in Windows Subsystem for Linux" src="/static/65b15eb608f5c4b3c8e1f45c40411cb3/302a4/WSLGUIAppsNoName.png" srcset="/static/65b15eb608f5c4b3c8e1f45c40411cb3/01bf6/WSLGUIAppsNoName.png 270w, /static/65b15eb608f5c4b3c8e1f45c40411cb3/07484/WSLGUIAppsNoName.png 540w, /static/65b15eb608f5c4b3c8e1f45c40411cb3/302a4/WSLGUIAppsNoName.png 1080w, /static/65b15eb608f5c4b3c8e1f45c40411cb3/0d292/WSLGUIAppsNoName.png 1620w, /static/65b15eb608f5c4b3c8e1f45c40411cb3/29114/WSLGUIAppsNoName.png 1920w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span> <em>Image from <a href="https://devblogs.microsoft.com/commandline/the-windows-subsystem-for-linux-build-2020-summary/">Microsoft’s official blog</a></em></p> <h2 id="winget-microsofts-package-manager" style="position:relative;"><a href="#winget-microsofts-package-manager" aria-label="winget microsofts package manager permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Winget, Microsoft’s package manager</h2> <p>This is probably one of those controversial topics where people will say: oh another package manager. But Microsoft believes they have considered all options and this decision was made with lots of considerations.</p> <p>You can install <code class="language-text">winget</code> via it’s <a href="https://www.microsoft.com/en-us/p/app-installer/9nblggh4nns1">App Installer</a> package. You can also join their insider program which contains the <code class="language-text">winget</code> by default.</p> <p>You can easily add your package to this package manager by following their instructions on their <a href="https://github.com/microsoft/winget-pkgs">GitHub repository</a> and create a PR containing your package’s information and link to download.</p> <p>Just so you know how excited people are, there are already <a href="https://github.com/microsoft/winget-pkgs/pulls"><strong>228</strong> open PR’s</a> and 541 closed. Of course not all of those PR’s have been packages, but even so, it’s a lot of packages submitted already.</p> <h2 id="microsofts-new-powertoys-run-launcher" style="position:relative;"><a href="#microsofts-new-powertoys-run-launcher" aria-label="microsofts new powertoys run launcher permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Microsoft’s new PowerToys Run launcher</h2> <p>Microsoft just released a new Spotlight-like launcher app for Windows 10. This launcher is part of a series of apps which come with the PowerToys tool set.</p> <p>It’s still preview, but you can install it today. Jump into <a href="https://github.com/microsoft/PowerToys/releases">this page</a> and download the <code class="language-text">msi</code> file, then install it.</p> <p>Or if you like to do it a bit more fancy, just run this in your terminal:</p> <div class="gatsby-code-button-container" data-toaster-id="72413276735515630000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`WinGet install powertoys`, `72413276735515630000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">WinGet <span class="token function">install</span> powertoys</code></pre></div> <p>Remember this requires <code class="language-text">winget</code> to be installed to work.</p> <p>Once installed, press <kbd>Alt</kbd> + <kbd>Space</kbd> and you’ll get this beautiful launcher:</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1080px; " > <a class="gatsby-resp-image-link" href="/static/cbddaf64a1326b5ade9c3837f1d05fbf/f04cb/powertoys.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 48.148148148148145%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAEEBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAZbMVDEH/8QAGBAAAwEBAAAAAAAAAAAAAAAAAgMEASD/2gAIAQEAAQUCmDGE6dYJ4//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABoQAAICAwAAAAAAAAAAAAAAAAECABEgUXH/2gAIAQEABj8CIbUZhV9x/8QAGRAAAgMBAAAAAAAAAAAAAAAAAREAICFB/9oACAEBAAE/IU2INpmQIOFX/9oADAMBAAIAAwAAABC0z//EABURAQEAAAAAAAAAAAAAAAAAABAR/9oACAEDAQE/EKf/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAbEAEAAwEAAwAAAAAAAAAAAAABABExQRBRkf/aAAgBAQABPxBOFQWna4kEZiS06GLGlx+xWtZR68f/2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Powertoys run launcher" title="Powertoys run launcher" src="/static/cbddaf64a1326b5ade9c3837f1d05fbf/47311/powertoys.jpg" srcset="/static/cbddaf64a1326b5ade9c3837f1d05fbf/6f81f/powertoys.jpg 270w, /static/cbddaf64a1326b5ade9c3837f1d05fbf/09d21/powertoys.jpg 540w, /static/cbddaf64a1326b5ade9c3837f1d05fbf/47311/powertoys.jpg 1080w, /static/cbddaf64a1326b5ade9c3837f1d05fbf/0047d/powertoys.jpg 1620w, /static/cbddaf64a1326b5ade9c3837f1d05fbf/274e1/powertoys.jpg 2160w, /static/cbddaf64a1326b5ade9c3837f1d05fbf/f04cb/powertoys.jpg 2955w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <blockquote> <p>💡 You need to run it manually for the first time for now. This will get fixed once they release their GA version.</p> </blockquote> <p>Alongside <em>PowerToys Run</em>, Microsoft also released a Keyboard Manager PowerToy which allows you to define shortcuts for your favourite actions, or remap keys like replacing <code class="language-text">A</code> with <code class="language-text">B</code>. Check out the other cool tools in their <a href="https://github.com/microsoft/PowerToys">GitHub page</a>.</p> <h2 id="project-reunion" style="position:relative;"><a href="#project-reunion" aria-label="project reunion permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Project Reunion</h2> <p>Microsoft announced <a href="https://github.com/microsoft/ProjectReunion">Project Reunion</a>, an effort to bring <code class="language-text">win32</code> desktop apps and its Universal Windows Platform (UWP) apps close together. From their page:</p> <blockquote> <p>Project Reunion makes it easier to build a great Windows app by providing a unified platform for new and existing Win32 and UWP apps. It will unify access to existing Win32 and UWP APIs and make them available decoupled from the OS, via tools like NuGet.</p> </blockquote> <p><img src="/68d2414da2d828e78d6ac2dbad1afb3c/projectreunion.gif" alt="Project Reunion"></p> <h2 id="fluid-framework" style="position:relative;"><a href="#fluid-framework" aria-label="fluid framework permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Fluid framework</h2> <p>Microsoft is adding a new type of document to it’s Office suite called <a href="https://techcommunity.microsoft.com/t5/microsoft-365-blog/introducing-the-first-microsoft-fluid-framework-experiences-in/ba-p/1345543">Fluid Framework</a>. This allows multiple people to collaborate on a single document with fast speed and offers multiple types of elements like tables, graphs and lists in one place rather than having to use multiple apps for different reasons.</p> <p>Apart from aforementioned features, it comes with ability to @mention someone to notify them of something, plus activity feeds for each document if you want to be notified of the changes.</p> <p>And to emphasise their focus in bringing more to open source, they are making this framework open too.</p> <h2 id="project-bonsai" style="position:relative;"><a href="#project-bonsai" aria-label="project bonsai permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Project Bonsai</h2> <p><a href="https://blogs.microsoft.com/ai-for-business/build-bonsai-public-preview/">Project Bonsai</a> is Microsoft’s effort in creating a platform which lets developers and engineers create autonomous systems. It is a machine teaching service to create and optimize intelligence for industrial control systems. Through machine teaching, subject matter experts without an AI background can break down their expertise into steps and tasks that are imparted to AI agents.</p> <h2 id="static-web-apps" style="position:relative;"><a href="#static-web-apps" aria-label="static web apps permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Static Web Apps</h2> <p><a href="https://docs.microsoft.com/en-us/azure/static-web-apps/overview">Static Web Apps</a> offers static Web applications powered by storage for hosting and Azure Functions as backend APIs. They also have the full pipeline on GitHub using GitHub actions to let you deploy your apps really fast.</p> <p>These are some of the key features:</p> <ul> <li><strong>Free web hosting</strong> for static content like HTML, CSS, JavaScript, and images.</li> <li><strong>Integrated API</strong> support provided by Azure Functions.</li> <li><strong>First-party GitHub integration</strong> where repository changes trigger builds and deployments.</li> <li><strong>Globally distributed</strong> static content, putting content closer to your users.</li> <li><strong>Free SSL certificates</strong>, which are automatically renewed.</li> <li><strong>Custom domains</strong> to provide branded customizations to your app.</li> <li><strong>Seamless security model</strong> with a reverse-proxy when calling APIs, which requires no CORS configuration.</li> <li><strong>Authentication provider integrations</strong> with Azure Active Directory, Facebook, Google, GitHub, and Twitter.</li> <li><strong>Customizable authorization role definition</strong> and assignments.</li> <li><strong>Back-end routing rules</strong> enabling full control over the content and routes you serve.</li> <li><strong>Generated staging versions</strong> powered by pull requests enabling preview versions of your site before publishing.</li> </ul> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 891px; " > <a class="gatsby-resp-image-link" href="/static/5aac7a911467f485db2f4e201d2cee65/b7877/static-apps-overview.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 43.7037037037037%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAAsSAAALEgHS3X78AAABGUlEQVQoz5VRSU7EQAzM/9/CbeCY+UU0B8QpOWSUtbP1lnTR5aEjhECAJcdtu1LeMu89juPAvu+g9H2Ptm0xDAOmSUmceaqPb+8saqUxrgbGWmzawEZ7HA9cxg8l2aIokOc5Xp4vuF5zaK0lHogJAWH3eLqNuLwqvPUat2aDtg5JTsJAcAj4Kp/jIWKdc6KrsUJk7MNPGCFMP/2mMnZc0bZtaJsG97rGMs8SS5jsu65+EmLZTR2JqqpCWZaRcBHCc2RjjByAx+ABuLM5VmUXewS6uHClFIijn/KMUenbDwx5MgbGcRRCJkhEf5om6YZEXddhXddzXBZO+FSk4Qrud2T4p5CMyoIskvxz5GVZJPFX5WicINn0Tvl3Qyy8Uw74eVoAAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Azure Static Web Apps" title="Azure Static Web Apps" src="/static/5aac7a911467f485db2f4e201d2cee65/b7877/static-apps-overview.png" srcset="/static/5aac7a911467f485db2f4e201d2cee65/01bf6/static-apps-overview.png 270w, /static/5aac7a911467f485db2f4e201d2cee65/07484/static-apps-overview.png 540w, /static/5aac7a911467f485db2f4e201d2cee65/b7877/static-apps-overview.png 891w" sizes="(max-width: 891px) 100vw, 891px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span> <em>Image from Microsoft blog</em></p> <h2 id="others" style="position:relative;"><a href="#others" aria-label="others permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Others</h2> <p>There were dozens of other stuff announced, but here are some of the developer related ones:</p> <ul> <li>Blazer WASM is released</li> <li>MAUI makes mobile app development easier</li> <li>Visual Studio is becoming Visual Studio Codespaces</li> <li>GitHub Codespaces brings amazing developer experience right from your browser</li> <li>GitHub Discussions for brainstorming feature ideas, help new users</li> <li>Code scanning and secret scanning on GitHub on private repositories</li> <li>GitHub Private Instances – a fully managed environment for enterprises</li> <li>GitHub Actions for Azure are now integrated within: Visual Studio Code, Azure CLI, and the Azure Portal. This makes it easier to deploy from GitHub to Azure!</li> </ul> <p>Hope this has given you some pointers to go play with some of these amazing features and till next time 👋🏽.</p><![CDATA[Swapping variables in JavaScript 🔁]]>https://yashints.dev/blog/2020/05/15/swaphttps://yashints.dev/blog/2020/05/15/swapFri, 15 May 2020 00:00:00 GMT<p> There may be many different reasons why you’d want to swap two variables be it just changing two item’s location in an array or when sorting collections. The traditional way is just define a new variable, assign one value to it, put one of the items in the old place, then put the temp variable back in the new place. But my question is, is that the only way?</p> <!--more--> <h2 id="traditionally" style="position:relative;"><a href="#traditionally" aria-label="traditionally permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Traditionally</h2> <p>The old way of swapping two variables is done like below:</p> <div class="gatsby-code-button-container" data-toaster-id="89892644180455960000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`let x = &quot;Yas&quot;; let y = &quot;Hints&quot;; let temp = x; x = y; y = temp; console.log(x); // Hints console.log(y); // Yas`, `89892644180455960000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">let</span> x <span class="token operator">=</span> <span class="token string">"Yas"</span><span class="token punctuation">;</span> <span class="token keyword">let</span> y <span class="token operator">=</span> <span class="token string">"Hints"</span><span class="token punctuation">;</span> <span class="token keyword">let</span> temp <span class="token operator">=</span> x<span class="token punctuation">;</span> x <span class="token operator">=</span> y<span class="token punctuation">;</span> y <span class="token operator">=</span> temp<span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Hints</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>y<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Yas</span></code></pre></div> <p>There is nothing wrong with this approach unless you’re doing it frequently.</p> <h2 id="without-the-temp-variable" style="position:relative;"><a href="#without-the-temp-variable" aria-label="without the temp variable permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Without the temp variable</h2> <p>There is another way you could swap two variables without any temp variable. But this only works with numbers:</p> <div class="gatsby-code-button-container" data-toaster-id="73956347536033090000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`let x = 10; let y = 20; x = x + y; y = x - y x = x - y; console.log(x); // 20 console.log(y); // 10`, `73956347536033090000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">let</span> x <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span> <span class="token keyword">let</span> y <span class="token operator">=</span> <span class="token number">20</span><span class="token punctuation">;</span> x <span class="token operator">=</span> x <span class="token operator">+</span> y<span class="token punctuation">;</span> y <span class="token operator">=</span> x <span class="token operator">-</span> y x <span class="token operator">=</span> x <span class="token operator">-</span> y<span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 20</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>y<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 10</span></code></pre></div> <p>This works two, but now we’re doing three additional operations to save some space, so you need to be careful when you use this one. Another thing to consider with this approach is the chance of having overflows with additions or subtractions (<code class="language-text">sum</code> should be less than <code class="language-text">Number.MAX_SAFE_INTEGER</code> which is <code class="language-text">9007199254740991</code>).</p> <h2 id="bitwise-code-classlanguage-textxorcode" style="position:relative;"><a href="#bitwise-code-classlanguage-textxorcode" aria-label="bitwise code classlanguage textxorcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Bitwise <code class="language-text">XOR</code></h2> <p>Similar to above approach, you could use <code class="language-text">XOR</code> to swap the two variables, but this also works only on numbers:</p> <div class="gatsby-code-button-container" data-toaster-id="37898359108258140000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`let x = 3; let y = 5; x = x ^ y; y = x ^ y; x = x ^ y; console.log(x); // 5 console.log(y); // 3`, `37898359108258140000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">let</span> x <span class="token operator">=</span> <span class="token number">3</span><span class="token punctuation">;</span> <span class="token keyword">let</span> y <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">;</span> x <span class="token operator">=</span> x <span class="token operator">^</span> y<span class="token punctuation">;</span> y <span class="token operator">=</span> x <span class="token operator">^</span> y<span class="token punctuation">;</span> x <span class="token operator">=</span> x <span class="token operator">^</span> y<span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 5</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>y<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 3</span></code></pre></div> <p>If you’re not familiar with <code class="language-text">XOR</code>, it works on bits. When you perform <code class="language-text">XOR</code> two bits, it evaluates to <code class="language-text">1</code> if they are different, and evaluates to <code class="language-text">0</code> if they’re the same.</p> <table> <thead> <tr> <th align="center">x</th> <th align="center">y</th> <th align="center">XOR</th> </tr> </thead> <tbody> <tr> <td align="center">0</td> <td align="center">0</td> <td align="center">0</td> </tr> <tr> <td align="center">1</td> <td align="center">1</td> <td align="center">0</td> </tr> <tr> <td align="center">0</td> <td align="center">1</td> <td align="center">1</td> </tr> <tr> <td align="center">1</td> <td align="center">0</td> <td align="center">1</td> </tr> </tbody> </table> <p>So let’s see why this works.</p> <ol> <li><code class="language-text">x = x ^ y</code></li> <li><code class="language-text">y = y ^ x</code> when <code class="language-text">x = (x ^ y)</code>, so the <code class="language-text">y = (x ^ y) ^ y</code> which equals to <code class="language-text">x ^ (y ^ y) = x ^ 0 = x</code>. So now our <code class="language-text">y</code> is the old <code class="language-text">x</code>.</li> <li><code class="language-text">x = x ^ y</code> when according to our first step <code class="language-text">x</code> is not <code class="language-text">x ^ y</code>, and so <code class="language-text">x = (x ^ y) ^ x = y ^ (x ^ x) = y ^ 0 = y</code>.</li> </ol> <p>Is this better than the previous one, probably faster, but still limited to numbers only.</p> <h2 id="es6-destructuring" style="position:relative;"><a href="#es6-destructuring" aria-label="es6 destructuring permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>ES6 destructuring</h2> <p>Destructuring is an <code class="language-text">ES6</code> feature which is used a lot in many of the modern frameworks. In its core, it allows you to store array elements in variables.</p> <div class="gatsby-code-button-container" data-toaster-id="49521831623408640000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`let x; let y; [x, y] = [1, 2, 3]; console.log(x); // 1 console.log(y); // 2`, `49521831623408640000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">let</span> x<span class="token punctuation">;</span> <span class="token keyword">let</span> y<span class="token punctuation">;</span> <span class="token punctuation">[</span>x<span class="token punctuation">,</span> y<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 1</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>y<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 2</span></code></pre></div> <p>Now considering how we can use this to swap the elements of an array:</p> <div class="gatsby-code-button-container" data-toaster-id="67670362288772460000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`let x = &quot;Yas&quot;; let y = &quot;Hints&quot;; [x, y] = [y , x]; console.log(x); // Hints console.log(y); // Yas`, `67670362288772460000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">let</span> x <span class="token operator">=</span> <span class="token string">"Yas"</span><span class="token punctuation">;</span> <span class="token keyword">let</span> y <span class="token operator">=</span> <span class="token string">"Hints"</span><span class="token punctuation">;</span> <span class="token punctuation">[</span>x<span class="token punctuation">,</span> y<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span>y <span class="token punctuation">,</span> x<span class="token punctuation">]</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Hints</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>y<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Yas</span></code></pre></div> <p>This method is much elegant, but still creates two arrays to perform the swapping. So the efficiency might not be that good if you’re swapping many elements.</p> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>Just because a feature is available, doesn’t mean you should use it in every situation. Think about what is the most important factor in the solution you’re implementing. If it’s space, choose one which doesn’t take much, although it’s a bit slower.</p> <p>If the memory doesn’t matter but speed is important, choose accordingly. But definitely consider the situation before deciding on your approach.</p><![CDATA[All you need to know about string in JavaScript 🧵]]>https://yashints.dev/blog/2020/05/11/stringhttps://yashints.dev/blog/2020/05/11/stringMon, 11 May 2020 00:00:00 GMT<p> <code class="language-text">String</code> is one of the primitive types in JavaScript and we use it in every project we work on no matter what. But how familiar are you with the methods available in JavaScript to work with a string variable? Let’s have a quick look at those in this article.</p> <!--more--> <h2 id="introduction" style="position:relative;"><a href="#introduction" aria-label="introduction permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Introduction</h2> <p>A primitive value such as “Yas” doesn’t have any methods or properties, mainly because it’s not an object. But with JavaScript, methods and properties are available because it treats primitive values as objects.</p> <p>Let’s have a look at the simplest method you have most definitely used:</p> <h2 id="string-length" style="position:relative;"><a href="#string-length" aria-label="string length permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>String length</h2> <p>The <code class="language-text">length</code> property returns the length of a string:</p> <div class="gatsby-code-button-container" data-toaster-id="90883526056431670000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const alphabet = &quot;ABCDEFGHIJKLMNOPQRSTUVWXYZ&quot;; console.log(alphabet.length); // 26`, `90883526056431670000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> alphabet <span class="token operator">=</span> <span class="token string">"ABCDEFGHIJKLMNOPQRSTUVWXYZ"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>alphabet<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 26</span></code></pre></div> <p>Pay attention on how <code class="language-text">length</code> property is available on a primitive type. Not all languages are following the same principle when dealing with such behaviour though. In <code class="language-text">PHP</code> we have helper functions:</p> <div class="gatsby-code-button-container" data-toaster-id="52604195884991365000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`<?php echo strlen(&quot;ABCDEFGHIJKLMNOPQRSTUVWXYZ&quot;); ?>`, `52604195884991365000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="php"><pre class="language-php"><code class="language-php"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span> <span class="token keyword">echo</span> <span class="token function">strlen</span><span class="token punctuation">(</span><span class="token double-quoted-string string">"ABCDEFGHIJKLMNOPQRSTUVWXYZ"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token delimiter important">?></span></span></code></pre></div> <h2 id="finding-a-text-in-string" style="position:relative;"><a href="#finding-a-text-in-string" aria-label="finding a text in string permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Finding a text in string</h2> <p>There are a few methods to help you find a sub-string in a <code class="language-text">String</code>. Let’s go through them and see what are their differences:</p> <h3 id="code-classlanguage-textindexofcode" style="position:relative;"><a href="#code-classlanguage-textindexofcode" aria-label="code classlanguage textindexofcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">indexOf</code></h3> <p>The <code class="language-text">indexOf</code> method returns the index of the <strong>first</strong> occurrence of a specified text in a string:</p> <div class="gatsby-code-button-container" data-toaster-id="48632242938187375000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;Can you find Yas in 'dryasdust'?&quot;; console.log(txt.indexOf('yas')); // 23`, `48632242938187375000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"Can you find Yas in 'dryasdust'?"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span><span class="token string">'yas'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 23</span></code></pre></div> <p>There a few points you need to know here. First, JavaScript counts positions from zero, and second, <code class="language-text">indexOf</code> is case sensitive.</p> <div class="gatsby-code-button-container" data-toaster-id="33655650919967850000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;Can you find Yas in 'dryasdust'?&quot;; console.log(txt.indexOf('Yas')); // 13`, `33655650919967850000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"Can you find Yas in 'dryasdust'?"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span><span class="token string">'Yas'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 13</span></code></pre></div> <p>This method returns <code class="language-text">-1</code> if it can’t find the text:</p> <div class="gatsby-code-button-container" data-toaster-id="98026277204439560000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;There is no 0 in 11&quot;; console.log(txt.indexOf('zero')); // -1`, `98026277204439560000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"There is no 0 in 11"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span><span class="token string">'zero'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// -1</span></code></pre></div> <p>You can pass a second argument to let the <code class="language-text">indexOf</code> know where to start looking for the text:</p> <div class="gatsby-code-button-container" data-toaster-id="15917152283273950000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;We have SQL and no-SQL databases!&quot;; console.log(txt.indexOf('SQl', 10)); // 19`, `15917152283273950000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"We have SQL and no-SQL databases!"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span><span class="token string">'SQl'</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 19</span></code></pre></div> <h3 id="code-classlanguage-textlastindexofcode" style="position:relative;"><a href="#code-classlanguage-textlastindexofcode" aria-label="code classlanguage textlastindexofcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">lastIndexOf</code></h3> <p>As the name suggests, <code class="language-text">lastIndexOf</code> is used to find the last occurrence of a text in a string.</p> <div class="gatsby-code-button-container" data-toaster-id="19308757719969915000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;Can you find Jam in 'JamStack'?&quot;; console.log(txt.indexOf('Jam')); // 21`, `19308757719969915000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"Can you find Jam in 'JamStack'?"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span><span class="token string">'Jam'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 21</span></code></pre></div> <p>This method also returns <code class="language-text">-1</code> if it can’t find the text you’re looking for, and takes a second parameter to start the search. However, since this method starts the search backward, the second parameter acts as cutting the string from that position to the end:</p> <div class="gatsby-code-button-container" data-toaster-id="20560648484854395000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;Can you find Jam in 'JamStack'?&quot;; console.log(txt.lastIndexOf('Jam', 6)); // -1`, `20560648484854395000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"Can you find Jam in 'JamStack'?"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">lastIndexOf</span><span class="token punctuation">(</span><span class="token string">'Jam'</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// -1</span></code></pre></div> <h3 id="code-classlanguage-textsearchcode" style="position:relative;"><a href="#code-classlanguage-textsearchcode" aria-label="code classlanguage textsearchcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">search</code></h3> <p>The <code class="language-text">search</code> method also searches the string for a text and returns the <strong>first</strong> occurrence of the text:</p> <div class="gatsby-code-button-container" data-toaster-id="73565247834760550000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;Can you find Jam in 'JamStack'?&quot;; console.log(txt.search('Jam')); // 13`, `73565247834760550000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"Can you find Jam in 'JamStack'?"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">search</span><span class="token punctuation">(</span><span class="token string">'Jam'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 13</span></code></pre></div> <p>You might think that <code class="language-text">search</code> and <code class="language-text">indexOf</code> are the same. However, there are differences in these two:</p> <ul> <li><code class="language-text">search</code> doesn’t accept any other parameter</li> <li><code class="language-text">indexOf</code> cannot take powerful search values such as regular expressions</li> </ul> <p>That’s right, <code class="language-text">search</code> will accept regex as argument as well, for example, to perform a case insensitive search you might want to use <code class="language-text">search</code> instead of <code class="language-text">indexOf</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="17146019495859500000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;There is Jam in JamStack!&quot;; console.log(str.search(/jam/i)); // 9 console.log(txt.indexOf('jam')); // -1`, `17146019495859500000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"There is Jam in JamStack!"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>str<span class="token punctuation">.</span><span class="token function">search</span><span class="token punctuation">(</span><span class="token regex">/jam/i</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 9</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span><span class="token string">'jam'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// -1</span></code></pre></div> <p>You can also search for non usual patterns, e.g. finding any character that is not a word or whitespace:</p> <div class="gatsby-code-button-container" data-toaster-id="75323537670152670000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;There is Jam in JamStack!&quot;; console.log(txt.search(/[^\w\s]/g)); // 24`, `75323537670152670000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"There is Jam in JamStack!"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">search</span><span class="token punctuation">(</span><span class="token regex">/[^\w\s]/g</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 24</span></code></pre></div> <h3 id="code-classlanguage-textendswithcode" style="position:relative;"><a href="#code-classlanguage-textendswithcode" aria-label="code classlanguage textendswithcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">endsWith</code></h3> <p>The <code class="language-text">endsWith</code> methods checks whether the string ends with the specified text. It returns <code class="language-text">true</code> if it does, and <code class="language-text">false</code> if it doesn’t:</p> <div class="gatsby-code-button-container" data-toaster-id="7675903992735900000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;There is Jam in JamStack!&quot;; console.log(txt.endsWith(&quot;Stack!&quot;)); // true`, `7675903992735900000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"There is Jam in JamStack!"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">endsWith</span><span class="token punctuation">(</span><span class="token string">"Stack!"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// true</span></code></pre></div> <blockquote> <p>💡 This method is case sensitive.</p> </blockquote> <h3 id="code-classlanguage-textstartswithcode" style="position:relative;"><a href="#code-classlanguage-textstartswithcode" aria-label="code classlanguage textstartswithcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">startsWith</code></h3> <p>Similar to <code class="language-text">endsWith</code>, this method checks whether a string starts with the specified text. This method is also case sensitive:</p> <div class="gatsby-code-button-container" data-toaster-id="9681930999698807000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;JamStack's got Jam&quot;; console.log(txt.startsWith(&quot;JamStack&quot;)); // true`, `9681930999698807000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"JamStack's got Jam"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">startsWith</span><span class="token punctuation">(</span><span class="token string">"JamStack"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// true</span></code></pre></div> <h3 id="code-classlanguage-textincludescode" style="position:relative;"><a href="#code-classlanguage-textincludescode" aria-label="code classlanguage textincludescode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">includes</code></h3> <p><code class="language-text">includes</code> allows you to check whether or not a string contains a specified text and is case sensitive:</p> <div class="gatsby-code-button-container" data-toaster-id="81588772676466180000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;There is Jam in JamStack!&quot;; console.log(txt.includes(&quot;in&quot;)); // true console.log(txt.includes(&quot;Jam&quot;)); // true console.log(txt.includes(&quot;jam&quot;)); // false`, `81588772676466180000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"There is Jam in JamStack!"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">"in"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// true</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">"Jam"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// true</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">"jam"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// false</span></code></pre></div> <h3 id="code-classlanguage-textlocalecomparecode" style="position:relative;"><a href="#code-classlanguage-textlocalecomparecode" aria-label="code classlanguage textlocalecomparecode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">localeCompare</code></h3> <p><code class="language-text">localeCompare</code> will compare two strings in the current locale. It returns a negative number indicating if the reference string occurs before the compare string, positive if it occurs after, and <code class="language-text">0</code> if they are equivalent:</p> <div class="gatsby-code-button-container" data-toaster-id="49198147497022140000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const a = 'réservé'; const b = 'RESERVE'; console.log(a.localeCompare(b)); // 1 console.log(a.localeCompare(b, 'en', { sensitivity: 'base' })); // 0`, `49198147497022140000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> a <span class="token operator">=</span> <span class="token string">'réservé'</span><span class="token punctuation">;</span> <span class="token keyword">const</span> b <span class="token operator">=</span> <span class="token string">'RESERVE'</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>a<span class="token punctuation">.</span><span class="token function">localeCompare</span><span class="token punctuation">(</span>b<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 1</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>a<span class="token punctuation">.</span><span class="token function">localeCompare</span><span class="token punctuation">(</span>b<span class="token punctuation">,</span> <span class="token string">'en'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> sensitivity<span class="token operator">:</span> <span class="token string">'base'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 0</span></code></pre></div> <h2 id="extracting-sub-strings" style="position:relative;"><a href="#extracting-sub-strings" aria-label="extracting sub strings permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Extracting sub-strings</h2> <p>There are three methods which allow you to extract part of a string.</p> <h3 id="code-classlanguage-textslicecode" style="position:relative;"><a href="#code-classlanguage-textslicecode" aria-label="code classlanguage textslicecode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">slice</code></h3> <p><code class="language-text">slice</code> extracts part of a string and returns the extracted part in a new string. It takes two arguments, start position, and end position (the end position will not be included).</p> <div class="gatsby-code-button-container" data-toaster-id="72883260074002770000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;There is Jam in JamStack!&quot;; console.log(txt.slice(9, 12)); // Jam`, `72883260074002770000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"There is Jam in JamStack!"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">12</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Jam</span></code></pre></div> <p>If you pass a negative value, it will start from the end of the string:</p> <div class="gatsby-code-button-container" data-toaster-id="92480748229390780000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;There is Jam in JamStack!&quot;; console.log(txt.slice(-16, -13)); // Jam`, `92480748229390780000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"There is Jam in JamStack!"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">16</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">13</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Jam</span></code></pre></div> <p>You can omit the second parameter, and it will extract from start to the end of the string:</p> <div class="gatsby-code-button-container" data-toaster-id="5807314790132101000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;There is Jam in JamStack!&quot;; console.log(txt.slice(16)); // JamStack!`, `5807314790132101000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"There is Jam in JamStack!"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// JamStack!</span></code></pre></div> <h3 id="code-classlanguage-textsubstringcode" style="position:relative;"><a href="#code-classlanguage-textsubstringcode" aria-label="code classlanguage textsubstringcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">substring</code></h3> <p>The <code class="language-text">substring</code> method is similar to <code class="language-text">slice</code> but it won’t accept negative indexes:</p> <div class="gatsby-code-button-container" data-toaster-id="75364498910922050000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;There is Jam in JamStack!&quot;; console.log(txt.substring(16)); // JamStack! console.log(txt.substring(9, 12)); // Jam`, `75364498910922050000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"There is Jam in JamStack!"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">substring</span><span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// JamStack!</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">substring</span><span class="token punctuation">(</span><span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">12</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Jam</span></code></pre></div> <h3 id="code-classlanguage-textsubstrcode" style="position:relative;"><a href="#code-classlanguage-textsubstrcode" aria-label="code classlanguage textsubstrcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">substr</code></h3> <p><code class="language-text">substr</code> method is similar to <code class="language-text">slice</code> with one difference that the second parameter is the length of the text to be extracted and not the position:</p> <div class="gatsby-code-button-container" data-toaster-id="53670619163099120000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;There is Jam in JamStack!&quot;; console.log(txt.substr(9, 3)); // Jam`, `53670619163099120000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"There is Jam in JamStack!"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">substr</span><span class="token punctuation">(</span><span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Jam</span></code></pre></div> <p>And if you omit the second parameter, it will extract to the end of the string. Furthermore, if the index you pass is negative, it will count from the end:</p> <div class="gatsby-code-button-container" data-toaster-id="9901674621974643000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;There is Jam in JamStack!&quot;; console.log(txt.substr(-9)); // JamStack!`, `9901674621974643000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"There is Jam in JamStack!"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">substr</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">9</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// JamStack!</span></code></pre></div> <h3 id="code-classlanguage-textsplitcode" style="position:relative;"><a href="#code-classlanguage-textsplitcode" aria-label="code classlanguage textsplitcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">split</code></h3> <p>Although this method is not directly used for extracting a text value, it’s good for splitting the string value by a character and return an array of substrings:</p> <div class="gatsby-code-button-container" data-toaster-id="83214929408026620000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;There is Jam in JamStack!&quot;; const words = txt.split(' '); console.log(words[4]); // JamStack!`, `83214929408026620000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"There is Jam in JamStack!"</span><span class="token punctuation">;</span> <span class="token keyword">const</span> words <span class="token operator">=</span> txt<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">' '</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>words<span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// JamStack!</span></code></pre></div> <p>A few points regarding this method:</p> <ul> <li>The simplest case is a single character, also referred to as delimiter. For example you can split a tab separated value (TSV) by using <code class="language-text">str.split(&quot;\t&quot;)</code>.</li> <li>If the separator contains multiple characters, that entire string needs to be found.</li> <li>If the separator cannot be found, the return value is an array with one element containing the whole string.</li> <li>If the separator appears at the beginning or end of the array, it still counts. Meaning the return value is an array with a string value, and one empty string item either at the start or at the end of the array.</li> <li>If you pass an empty string <code class="language-text">&quot;</code> as the separator, it splits the string into single UTF-16 characters.</li> </ul> <div class="gatsby-code-button-container" data-toaster-id="78999578034584370000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;There is Jam in JamStack!&quot;; console.log(txt.split('Jam')); // [&quot;There is &quot;, &quot; in &quot;, &quot;Stack!&quot;] console.log(txt.split('test')); // [&quot;There is Jam in JamStack!&quot;] console.log(txt.split('There')); // [&quot;&quot;, &quot; is Jam in JamStack!&quot;] console.log(txt.split('')); // [&quot;T&quot;, &quot;h&quot;, &quot;e&quot;, &quot;r&quot;, &quot;e&quot;, &quot; &quot;, &quot;i&quot;, &quot;s&quot;, &quot; &quot;, &quot;J&quot;, &quot;a&quot;, &quot;m&quot;, &quot; &quot;, &quot;i&quot;, &quot;n&quot;, &quot; &quot;, &quot;J&quot;, &quot;a&quot;, &quot;m&quot;, &quot;S&quot;, &quot;t&quot;, &quot;a&quot;, &quot;c&quot;, &quot;k&quot;, &quot;!&quot;]`, `78999578034584370000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"There is Jam in JamStack!"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">'Jam'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// ["There is ", " in ", "Stack!"]</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">'test'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// ["There is Jam in JamStack!"]</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">'There'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// ["", " is Jam in JamStack!"]</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// ["T", "h", "e", "r", "e", " ", "i", "s", " ", "J", "a", "m", " ", "i", "n", " ", "J", "a", "m", "S", "t", "a", "c", "k", "!"]</span></code></pre></div> <h2 id="replacing-string-content" style="position:relative;"><a href="#replacing-string-content" aria-label="replacing string content permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Replacing string content</h2> <p>The <code class="language-text">replace</code> method, as the name suggests, replaces a part of the string with the provided text:</p> <div class="gatsby-code-button-container" data-toaster-id="61263962420208394000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;Who's awesome!&quot;; console.log(txt.replace(&quot;Who's&quot;, &quot;You're&quot;)); // You're awesome!`, `61263962420208394000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"Who's awesome!"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token string">"Who's"</span><span class="token punctuation">,</span> <span class="token string">"You're"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// You're awesome!</span></code></pre></div> <blockquote> <p>💡 This method doesn’t change the original string, it returns a new one. </p> </blockquote> <p>By default, it’s <strong>case sensitive</strong> and just replaces the <strong>first</strong> match:</p> <div class="gatsby-code-button-container" data-toaster-id="65477130985428340000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;This 🐶 is a good 🐶!&quot;; console.log(txt.replace(&quot;This&quot;, &quot;That&quot;)); // This 🐶 is a good 🐶! console.log(txt.replace(&quot;🐶&quot;, &quot;🐕‍🦺&quot;)); // This 🐕‍🦺 is a good 🐶!`, `65477130985428340000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"This 🐶 is a good 🐶!"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token string">"This"</span><span class="token punctuation">,</span> <span class="token string">"That"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// This 🐶 is a good 🐶!</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token string">"🐶"</span><span class="token punctuation">,</span> <span class="token string">"🐕‍🦺"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// This 🐕‍🦺 is a good 🐶!</span></code></pre></div> <p>To do a case insensitive replace or to replace all matches, you could use regex:</p> <div class="gatsby-code-button-container" data-toaster-id="74434583751386140000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;This 🐶 is a good 🐶!&quot;; console.log(txt.replace(/THIS/i, &quot;That&quot;)); // That 🐶 is a good 🐶! console.log(txt.replace(/🐶/g, &quot;🐩&quot;)); // This 🐩 is a good 🐩!`, `74434583751386140000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"This 🐶 is a good 🐶!"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex">/THIS/i</span><span class="token punctuation">,</span> <span class="token string">"That"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// That 🐶 is a good 🐶!</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex">/🐶/g</span><span class="token punctuation">,</span> <span class="token string">"🐩"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// This 🐩 is a good 🐩!</span></code></pre></div> <h2 id="case-conversion" style="position:relative;"><a href="#case-conversion" aria-label="case conversion permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Case conversion</h2> <p>To convert a string to uppercase or lowercase you can use <code class="language-text">toUpperCase</code> and <code class="language-text">toLowerCase</code> respectively:</p> <div class="gatsby-code-button-container" data-toaster-id="33763221039215784000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;What's up bro!&quot;; console.log(txt.toLowerCase()); // what's up bro! console.log(txt.toUpperCase()); // WHAT'S UP BRO!`, `33763221039215784000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"What's up bro!"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// what's up bro!</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">toUpperCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// WHAT'S UP BRO!</span></code></pre></div> <p>We also have <code class="language-text">toLocaleLowerCase</code> and <code class="language-text">toLocaleUpperCase</code> methods to convert according to user’s current locale:</p> <div class="gatsby-code-button-container" data-toaster-id="16381309679526623000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const dotted = 'İstanbul'; console.log(\`EN-US: \${dotted.toLocaleLowerCase('en-US')}\`); // &quot;i̇stanbul&quot; console.log(\`TR: \${dotted.toLocaleLowerCase('tr')}\`); // &quot;İSTANBUL&quot;`, `16381309679526623000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> dotted <span class="token operator">=</span> <span class="token string">'İstanbul'</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">EN-US: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>dotted<span class="token punctuation">.</span><span class="token function">toLocaleLowerCase</span><span class="token punctuation">(</span><span class="token string">'en-US'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "i̇stanbul"</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">TR: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>dotted<span class="token punctuation">.</span><span class="token function">toLocaleLowerCase</span><span class="token punctuation">(</span><span class="token string">'tr'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "İSTANBUL"</span></code></pre></div> <h2 id="concatenation" style="position:relative;"><a href="#concatenation" aria-label="concatenation permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Concatenation</h2> <p>You can use <code class="language-text">concat</code> to join two strings together (like <code class="language-text">+</code> operator):</p> <div class="gatsby-code-button-container" data-toaster-id="40707249243862950000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`let message = &quot;Hello&quot; + &quot; &quot; + &quot;World!&quot;; console.log(message); // Hello World! message = &quot;Hello&quot;.concat(&quot; &quot;, &quot;World!&quot;); console.log(message); // Hello World!`, `40707249243862950000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">let</span> message <span class="token operator">=</span> <span class="token string">"Hello"</span> <span class="token operator">+</span> <span class="token string">" "</span> <span class="token operator">+</span> <span class="token string">"World!"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Hello World!</span> message <span class="token operator">=</span> <span class="token string">"Hello"</span><span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span><span class="token string">" "</span><span class="token punctuation">,</span> <span class="token string">"World!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Hello World!</span></code></pre></div> <h2 id="trimming-and-padding" style="position:relative;"><a href="#trimming-and-padding" aria-label="trimming and padding permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Trimming and padding</h2> <h3 id="code-classlanguage-texttrimcode" style="position:relative;"><a href="#code-classlanguage-texttrimcode" aria-label="code classlanguage texttrimcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">trim</code></h3> <p>To remove whitespace from both sides of a string value, you can use the <code class="language-text">trim</code> function:</p> <div class="gatsby-code-button-container" data-toaster-id="86728788942639500000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`let message = &quot; Hello World! &quot;; console.log(message.trim()); // &quot;Hello World!&quot;`, `86728788942639500000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">let</span> message <span class="token operator">=</span> <span class="token string">" Hello World! "</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>message<span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "Hello World!"</span></code></pre></div> <blockquote> <p>💡 Whitespace in this context is all the whitespace characters (space, tab, no-break space, etc.).</p> </blockquote> <h3 id="code-classlanguage-textpadstartcode" style="position:relative;"><a href="#code-classlanguage-textpadstartcode" aria-label="code classlanguage textpadstartcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">padStart</code></h3> <p>The <code class="language-text">padStart</code> method adds a given string at the start of the original string (multiple times, if needed), until the resulting string reaches the given length.</p> <div class="gatsby-code-button-container" data-toaster-id="43892574533421520000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const str1 = '5'; console.log(str1.padStart(6, '0')); // 000005`, `43892574533421520000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> str1 <span class="token operator">=</span> <span class="token string">'5'</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>str1<span class="token punctuation">.</span><span class="token function">padStart</span><span class="token punctuation">(</span><span class="token number">6</span><span class="token punctuation">,</span> <span class="token string">'0'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 000005</span></code></pre></div> <h3 id="code-classlanguage-textpadendcode" style="position:relative;"><a href="#code-classlanguage-textpadendcode" aria-label="code classlanguage textpadendcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">padEnd</code></h3> <p>The opposite of <code class="language-text">padStart</code> is the <code class="language-text">padEnd</code>. </p> <div class="gatsby-code-button-container" data-toaster-id="44465912912324575000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = 'OMG Jam'; console.log(txt.padEnd(25, '.')); // OMG Jam.................. console.log('OMG Jam'.padEnd(10)); // &quot;OMG Jam &quot;`, `44465912912324575000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">'OMG Jam'</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">padEnd</span><span class="token punctuation">(</span><span class="token number">25</span><span class="token punctuation">,</span> <span class="token string">'.'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// OMG Jam..................</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'OMG Jam'</span><span class="token punctuation">.</span><span class="token function">padEnd</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "OMG Jam "</span></code></pre></div> <h2 id="getting-the-string-value" style="position:relative;"><a href="#getting-the-string-value" aria-label="getting the string value permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Getting the string value</h2> <p>There are two methods where you can get the value of a string in JavaScript. You might say, Yas are you crazy, we already have the value in the variable. But remember that I said JavaScript treats a string variable as an object under the hood, so these methods come from the <code class="language-text">Object.prototype</code>.</p> <h3 id="code-classlanguage-textvalueofcode" style="position:relative;"><a href="#code-classlanguage-textvalueofcode" aria-label="code classlanguage textvalueofcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">valueOf</code></h3> <p>The <code class="language-text">valueOf</code> returns the primitive value of an object. For string values, JavaScript does it for you under the hood whenever you invoke a method which needs the primitive value. But you can also call this method to get it:</p> <div class="gatsby-code-button-container" data-toaster-id="60443929932604860000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;Yas&quot;; console.log(txt.valueOf()); // &quot;Yas&quot;`, `60443929932604860000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"Yas"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "Yas"</span></code></pre></div> <h3 id="code-classlanguage-texttostringcode" style="position:relative;"><a href="#code-classlanguage-texttostringcode" aria-label="code classlanguage texttostringcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">toString</code></h3> <p>Similar to the above method, <code class="language-text">toString</code> is used to return the value of a string.</p> <div class="gatsby-code-button-container" data-toaster-id="81802971226397790000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const stringObj = new String('Yas'); console.log(stringObj); // String {&quot;Yas&quot;} console.log(stringObj.toString()); // &quot;Yas&quot;`, `81802971226397790000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> stringObj <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">String</span><span class="token punctuation">(</span><span class="token string">'Yas'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>stringObj<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// String {"Yas"}</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>stringObj<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "Yas"</span></code></pre></div> <h2 id="code-classlanguage-textrepeatcode" style="position:relative;"><a href="#code-classlanguage-textrepeatcode" aria-label="code classlanguage textrepeatcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">repeat</code></h2> <p>This method is my personal favourite. You can pass a number to the <code class="language-text">repeat</code> method and it returns your string repeated by that number. It’s really good if you want to have some long text generated for testing purposes:</p> <div class="gatsby-code-button-container" data-toaster-id="24242936912285670000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;Lorem ipsum faked,&quot;; console.log(txt.repeat(5)); // Lorem ipsum faked,Lorem ipsum faked,Lorem ipsum faked,Lorem ipsum faked,Lorem ipsum faked,`, `24242936912285670000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"Lorem ipsum faked,"</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>txt<span class="token punctuation">.</span><span class="token function">repeat</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Lorem ipsum faked,Lorem ipsum faked,Lorem ipsum faked,Lorem ipsum faked,Lorem ipsum faked,</span></code></pre></div> <h2 id="character-methods" style="position:relative;"><a href="#character-methods" aria-label="character methods permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Character methods</h2> <h3 id="code-classlanguage-textcharatcode" style="position:relative;"><a href="#code-classlanguage-textcharatcode" aria-label="code classlanguage textcharatcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">charAt</code></h3> <p>The <code class="language-text">charAt</code> returns a new string consisting of the single UTF-16 code unit which is located at the index specified:</p> <div class="gatsby-code-button-container" data-toaster-id="24176577267161092000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;There is Jam in JamStack!&quot;; const index = 4; console.log(\`The character at index \${index} is \${txt.charAt(index)}\`); // &quot;The character at index 4 is r&quot;`, `24176577267161092000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"There is Jam in JamStack!"</span><span class="token punctuation">;</span> <span class="token keyword">const</span> index <span class="token operator">=</span> <span class="token number">4</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">The character at index </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>index<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> is </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>txt<span class="token punctuation">.</span><span class="token function">charAt</span><span class="token punctuation">(</span>index<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "The character at index 4 is r"</span></code></pre></div> <h3 id="code-classlanguage-textcharcodeatcode" style="position:relative;"><a href="#code-classlanguage-textcharcodeatcode" aria-label="code classlanguage textcharcodeatcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">charCodeAt</code></h3> <p>The <code class="language-text">charCodeAt</code> returns an integer between <code class="language-text">0</code> and <code class="language-text">65535</code> representing the UTF-16 code unit at the given index:</p> <div class="gatsby-code-button-container" data-toaster-id="62064928965041990000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const txt = &quot;There is Jam in JamStack!&quot;; const index = 4; console.log(\`The character code at index \${index} is \${txt.charCodeAt(index)}\`); //The character code at index 4 is 101`, `62064928965041990000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> txt <span class="token operator">=</span> <span class="token string">"There is Jam in JamStack!"</span><span class="token punctuation">;</span> <span class="token keyword">const</span> index <span class="token operator">=</span> <span class="token number">4</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">The character code at index </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>index<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> is </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>txt<span class="token punctuation">.</span><span class="token function">charCodeAt</span><span class="token punctuation">(</span>index<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//The character code at index 4 is 101</span></code></pre></div> <h3 id="code-classlanguage-textcodepointatcode" style="position:relative;"><a href="#code-classlanguage-textcodepointatcode" aria-label="code classlanguage textcodepointatcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">codePointAt</code></h3> <p>The <code class="language-text">codePointAt</code> method returns a non negative integer representing the Unicode point value of the specified index:</p> <div class="gatsby-code-button-container" data-toaster-id="5882995428038385000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const icons = '☃★♲'; console.log(icons.codePointAt(1)); // &quot;9733&quot; '\uD800\uDC00'.codePointAt(0) // 65536`, `5882995428038385000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> icons <span class="token operator">=</span> <span class="token string">'☃★♲'</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>icons<span class="token punctuation">.</span><span class="token function">codePointAt</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "9733" </span> <span class="token string">'\uD800\uDC00'</span><span class="token punctuation">.</span><span class="token function">codePointAt</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token comment">// 65536</span></code></pre></div> <h2 id="code-classlanguage-textnormalizecode" style="position:relative;"><a href="#code-classlanguage-textnormalizecode" aria-label="code classlanguage textnormalizecode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">normalize</code></h2> <p>And last, but not least, the <code class="language-text">normalize</code> method returns the Unicode normalisation form of a string:</p> <div class="gatsby-code-button-container" data-toaster-id="95512610887892270000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const myAlias = '\u0059\u0061\u0073\u0068\u0069\u006e\u0074\u0073'; console.log(\`\${myAlias}\`); // Yashints`, `95512610887892270000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> myAlias <span class="token operator">=</span> <span class="token string">'\u0059\u0061\u0073\u0068\u0069\u006e\u0074\u0073'</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>myAlias<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Yashints</span></code></pre></div> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>Hope you enjoyed reading this and learnt a few tricks which could help you at what you do day to day. And let’s finish this article with a joke:</p> <blockquote> <p>What do you call it when Wilhelm II makes a string of bad puns? 👉🏽 A Kaiser roll</p> </blockquote><![CDATA[Let's sort with JavaScript 🔢]]>https://yashints.dev/blog/2020/05/03/sortinghttps://yashints.dev/blog/2020/05/03/sortingSun, 03 May 2020 00:00:00 GMT<p> There are many different sorting algorithms out there such as quick sort, merge sort, insertion sort, bubble sort, etc., that could be useful in our day to day life, writing code which gets shipped to production. Knowing all of them is not necessary, but if you have a basic understanding of each one, you can decide on the most efficient one for your scenario.</p> <!--more--> <h2 id="introduction" style="position:relative;"><a href="#introduction" aria-label="introduction permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Introduction</h2> <p>Choosing a suboptimal sort algorithm could lead to longer completion time, code complexity, or worse, a program that crashes half way through an operation.</p> <p>We use sorting algorithms everyday, <code class="language-text">Array.sort</code> is one of the sort algorithms which is used to sort an array in ascending order. But that is not a solution for every scenario. </p> <p>When choosing a sorting algorithm, we need to consider the complexity, or the number of operations performed (usually mentioned as <code class="language-text">O(x)</code>, which is read Big O of x) and also number of swaps along the way. So let’s review and implement some of the most used ones together and learn about their complexity.</p> <h2 id="bubble-sort" style="position:relative;"><a href="#bubble-sort" aria-label="bubble sort permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Bubble sort</h2> <p>The way bubble sort works is very simple. You compare the first item of the collection with the second. If the first one is bigger, then swap the two. If not, move to the second item, and repeat the same. We keep repeating this until we reach the end of the list.</p> <p>So far we have bubbled up the biggest item of the list to the far right side in its position. Now we repeat this for the rest of the items again until the list is sorted.</p> <p>Let’s see this in action:</p> <p><img src="/d4c88b8cc620af6af67c33910899fcf7/bubblesort.gif" alt="Bubble sort in action"></p> <div class="gatsby-code-button-container" data-toaster-id="56984869929764790000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`function bubbleSort(list) { let len = list.length; for(let i = len - 1; i >= 0; i--) { for(let j = 1; j <= i; j++) { if(list[j - 1] > list[j]) { let temp = list[j - 1]; list[j - 1] = list[j]; list[j] = temp; } } } return list; } bubbleSort([7, 5, 2, 3, 9, 6]); // [2, 3, 5, 6, 7, 9]`, `56984869929764790000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">bubbleSort</span><span class="token punctuation">(</span><span class="token parameter">list</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> len <span class="token operator">=</span> list<span class="token punctuation">.</span>length<span class="token punctuation">;</span> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> len <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span> i <span class="token operator">>=</span> <span class="token number">0</span><span class="token punctuation">;</span> i<span class="token operator">--</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">let</span> j <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> j <span class="token operator">&lt;=</span> i<span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span><span class="token punctuation">(</span>list<span class="token punctuation">[</span>j <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">></span> list<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> temp <span class="token operator">=</span> list<span class="token punctuation">[</span>j <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span> list<span class="token punctuation">[</span>j <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">=</span> list<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">;</span> list<span class="token punctuation">[</span>j<span class="token punctuation">]</span> <span class="token operator">=</span> temp<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> list<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">bubbleSort</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// [2, 3, 5, 6, 7, 9]</span></code></pre></div> <p>As you can see this algorithm is not optimal, in fact it is one of the heaviest in terms of number of operations in worst-case scenarios. But in terms of swaps, it’s one of the best since it sorts in place.</p> <p>The complexity of bubble sort in worst-case is <strong>O(n<sup>2</sup>)</strong>, read as <code class="language-text">big O of n square</code>, where <code class="language-text">n</code> is the number of items in the collection.</p> <p>However, in a best case scenario (already sorted collections), it will be <strong>O(n)</strong> with <strong>O(1)</strong> swaps.</p> <table> <thead> <tr> <th>Case</th> <th>Complexity</th> </tr> </thead> <tbody> <tr> <td>Worst-case performance</td> <td>O(n<sup>2</sup>) comparisons</td> </tr> <tr> <td></td> <td>O(n<sup>2</sup>) swaps</td> </tr> <tr> <td>Best-case performance</td> <td>O(n) comparisons</td> </tr> <tr> <td></td> <td>O(1) swaps</td> </tr> <tr> <td>Average-case performance</td> <td>O(n<sup>2</sup>) comparisons</td> </tr> <tr> <td></td> <td>O(n<sup>2</sup>) swaps</td> </tr> </tbody> </table> <h2 id="selection-sort" style="position:relative;"><a href="#selection-sort" aria-label="selection sort permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Selection sort</h2> <p>Selection sort is really simple like bubble sort. We go through the list, find the index of the lowest element, then swap the lowest element with the first one. Now that the first item is sorted, we repeat this for all remaining elements.</p> <p>Let’s see this in action:</p> <p><img src="/f20b8898585b3ca03843d93ce2c35a68/selectionsort.gif" alt="Selection sort in action"></p> <div class="gatsby-code-button-container" data-toaster-id="71401167238120840000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`function selectionSort(list) { let minIndex, temp, len = list.length; for(let i = 0; i < len; i++) { minIndex = i; for(let j = i+1; j < len; j++) { if(list[j] < list[minIndex]) { minIndex = j; } } temp = list[i]; list[i] = list[minIndex]; list[minIndex] = temp; } return list; } selectionSort([11, 25, 12, 22, 64]); //[11, 12, 22, 25, 64]`, `71401167238120840000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">selectionSort</span><span class="token punctuation">(</span><span class="token parameter">list</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> minIndex<span class="token punctuation">,</span> temp<span class="token punctuation">,</span> len <span class="token operator">=</span> list<span class="token punctuation">.</span>length<span class="token punctuation">;</span> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> len<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> minIndex <span class="token operator">=</span> i<span class="token punctuation">;</span> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">let</span> j <span class="token operator">=</span> i<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">;</span> j <span class="token operator">&lt;</span> len<span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span><span class="token punctuation">(</span>list<span class="token punctuation">[</span>j<span class="token punctuation">]</span> <span class="token operator">&lt;</span> list<span class="token punctuation">[</span>minIndex<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> minIndex <span class="token operator">=</span> j<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> temp <span class="token operator">=</span> list<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span> list<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> list<span class="token punctuation">[</span>minIndex<span class="token punctuation">]</span><span class="token punctuation">;</span> list<span class="token punctuation">[</span>minIndex<span class="token punctuation">]</span> <span class="token operator">=</span> temp<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> list<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">selectionSort</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">11</span><span class="token punctuation">,</span> <span class="token number">25</span><span class="token punctuation">,</span> <span class="token number">12</span><span class="token punctuation">,</span> <span class="token number">22</span><span class="token punctuation">,</span> <span class="token number">64</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//[11, 12, 22, 25, 64]</span></code></pre></div> <p>Let’s see how the list is sorted in each iteration in the above example:</p> <table> <thead> <tr> <th>Sorted list</th> <th>Unsorted sublist</th> <th>Lowest elements</th> </tr> </thead> <tbody> <tr> <td>[]</td> <td>[11, 25, 12, 22, 64]</td> <td>11</td> </tr> <tr> <td>[11]</td> <td>[25, 12, 22, 64]</td> <td>12</td> </tr> <tr> <td>[11, 12]</td> <td>[25, 22, 64]</td> <td>22</td> </tr> <tr> <td>[11, 12, 22]</td> <td>[25, 64]</td> <td>25</td> </tr> <tr> <td>[11, 12, 22, 25]</td> <td>[64]</td> <td>64</td> </tr> <tr> <td>[11, 12, 22, 25, 64]</td> <td>[]</td> <td></td> </tr> </tbody> </table> <p>In terms of complexity, this algorithm remains the same regardless of which scenario we’re facing. Which is <strong>O(n<sup>2</sup>)</strong> for comparisons, and <strong>O(n)</strong> swaps. But if you look at the code, it’s self explanatory and simple and sometimes we just want exactly that. In terms or swaps, it’s less than bubble sort.</p> <table> <thead> <tr> <th>Case</th> <th>Complexity</th> </tr> </thead> <tbody> <tr> <td>Worst-case performance</td> <td>O(n<sup>2</sup>) comparisons</td> </tr> <tr> <td></td> <td>O(n) swaps</td> </tr> <tr> <td>Best-case performance</td> <td>O(n<sup>2</sup>) comparisons</td> </tr> <tr> <td></td> <td>O(n) swaps</td> </tr> <tr> <td>Average-case performance</td> <td>O(n<sup>2</sup>) comparisons</td> </tr> <tr> <td></td> <td>O(n) swaps</td> </tr> </tbody> </table> <h2 id="insertion-sort" style="position:relative;"><a href="#insertion-sort" aria-label="insertion sort permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Insertion sort</h2> <p>This is like when I play cards and someone is handing me the them one by one. I usually put them in my hand in order as I receive them. Insertion sort builds the final list one item at a time. This means it’s less efficient for large lists relative to it’s competitors such as quick sort, or merge sort.</p> <p>However, it provides several advantages:</p> <ul> <li>Simple implementation (we’ll get there shortly).</li> <li>Efficient for small data sets.</li> <li>More efficient than bubble or selection sorts.</li> <li>Adaptive, i.e. efficient for already sorted collections.</li> <li>In place.</li> <li>Online, can sort a list as it receives it.</li> </ul> <p>Let’s see how it works in action:</p> <p><img src="/6e67d1c722106442b422ee53e98575b3/insertionsort.gif" alt="selection sort in action"></p> <div class="gatsby-code-button-container" data-toaster-id="90300139591522860000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`function insertionSort(list){ let i, len = list.length, item, j; for(i = 1; i < len; i++){ item = list[i]; j = i; while(j > 0 && list[j-1] > item) { list[j] = list[j-1]; j--; } list[j] = item; } return list; }`, `90300139591522860000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">insertionSort</span><span class="token punctuation">(</span><span class="token parameter">list</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">let</span> i<span class="token punctuation">,</span> len <span class="token operator">=</span> list<span class="token punctuation">.</span>length<span class="token punctuation">,</span> item<span class="token punctuation">,</span> j<span class="token punctuation">;</span> <span class="token keyword">for</span><span class="token punctuation">(</span>i <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> len<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span> item <span class="token operator">=</span> list<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span> j <span class="token operator">=</span> i<span class="token punctuation">;</span> <span class="token keyword">while</span><span class="token punctuation">(</span>j <span class="token operator">></span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> list<span class="token punctuation">[</span>j<span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">></span> item<span class="token punctuation">)</span> <span class="token punctuation">{</span> list<span class="token punctuation">[</span>j<span class="token punctuation">]</span> <span class="token operator">=</span> list<span class="token punctuation">[</span>j<span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span> j<span class="token operator">--</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> list<span class="token punctuation">[</span>j<span class="token punctuation">]</span> <span class="token operator">=</span> item<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> list<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div> <p>In terms of complexity, it’s similar to bubble sort in worst and average cases with <strong>O(n<sup>2</sup>)</strong> for both comparisons and swaps. But in best case, it’s really efficient with <strong>O(n)</strong> comparisons and <strong>O(1)</strong> swaps.</p> <table> <thead> <tr> <th>Case</th> <th>Complexity</th> </tr> </thead> <tbody> <tr> <td>Worst-case performance</td> <td>O(n<sup>2</sup>) comparisons</td> </tr> <tr> <td></td> <td>O(n<sup>2</sup>) swaps</td> </tr> <tr> <td>Best-case performance</td> <td>O(n) comparisons</td> </tr> <tr> <td></td> <td>O(1) swaps</td> </tr> <tr> <td>Average-case performance</td> <td>O(n<sup>2</sup>) comparisons</td> </tr> <tr> <td></td> <td>O(n<sup>2</sup>) swaps</td> </tr> </tbody> </table> <h2 id="merge-sort" style="position:relative;"><a href="#merge-sort" aria-label="merge sort permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Merge sort</h2> <p>Merge sort is in the divide and conquer algorithms and is implemented with a recursive pattern. We break down the list into small pieces until you have one item in each piece. Then we merge them back together but will compare them and put the items in order.</p> <p>It’s really easy to understand, but let’s see it in action:</p> <p><img src="/a29c0dd0186d1f8cef3c5ebdedf3e5a3/mergesort.gif" alt="merge sort in action"></p> <div class="gatsby-code-button-container" data-toaster-id="22879255029963887000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`function mergeSort(list) { let len = list.length; if(len < 2) return list; let mid = Math.floor(len/2), left = list.slice(0,mid), right =list.slice(mid); return merge(mergeSort(left),mergeSort(right)); } function merge(left, right) { let result = [], lLen = left.length, rLen = right.length, l = 0, r = 0; while(l < lLen && r < rLen) { if(left[l] < right[r]) { result.push(left[l++]); } else{ result.push(right[r++]); } } return result.concat(left.slice(l)).concat(right.slice(r)); }`, `22879255029963887000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">mergeSort</span><span class="token punctuation">(</span><span class="token parameter">list</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> len <span class="token operator">=</span> list<span class="token punctuation">.</span>length<span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span>len <span class="token operator">&lt;</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token keyword">return</span> list<span class="token punctuation">;</span> <span class="token keyword">let</span> mid <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>len<span class="token operator">/</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span> left <span class="token operator">=</span> list<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span>mid<span class="token punctuation">)</span><span class="token punctuation">,</span> right <span class="token operator">=</span>list<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span>mid<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">merge</span><span class="token punctuation">(</span><span class="token function">mergeSort</span><span class="token punctuation">(</span>left<span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token function">mergeSort</span><span class="token punctuation">(</span>right<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">merge</span><span class="token punctuation">(</span><span class="token parameter">left<span class="token punctuation">,</span> right</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> result <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> lLen <span class="token operator">=</span> left<span class="token punctuation">.</span>length<span class="token punctuation">,</span> rLen <span class="token operator">=</span> right<span class="token punctuation">.</span>length<span class="token punctuation">,</span> l <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">,</span> r <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">while</span><span class="token punctuation">(</span>l <span class="token operator">&lt;</span> lLen <span class="token operator">&amp;&amp;</span> r <span class="token operator">&lt;</span> rLen<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span><span class="token punctuation">(</span>left<span class="token punctuation">[</span>l<span class="token punctuation">]</span> <span class="token operator">&lt;</span> right<span class="token punctuation">[</span>r<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> result<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>left<span class="token punctuation">[</span>l<span class="token operator">++</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span><span class="token punctuation">{</span> result<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>right<span class="token punctuation">[</span>r<span class="token operator">++</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> result<span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span>left<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span>l<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span>right<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span>r<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div> <p>Merge sort is much better in terms of complexity from previous algorithms. It takes <strong>O(n log n)</strong> operations to sort an array. In terms of memory needed, it’s <strong>O(n)</strong> total with <strong>O(n)</strong> auxiliary if we use array and <strong>O(1)</strong> if we use a linked list.</p> <table> <thead> <tr> <th>Case</th> <th>Complexity</th> </tr> </thead> <tbody> <tr> <td>Worst-case performance</td> <td>O(n log n)</td> </tr> <tr> <td>Best-case performance</td> <td>O(n log n)</td> </tr> <tr> <td>Average-case performance</td> <td>O(n log n)</td> </tr> <tr> <td>Worst-case space</td> <td>O(n) total, O(n) auxiliary with list, O(1) with linked list</td> </tr> </tbody> </table> <h2 id="quick-sort" style="position:relative;"><a href="#quick-sort" aria-label="quick sort permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Quick sort</h2> <p>Quick sort is similar to merge sort, with the difference that the we don’t split the collection in half. We choose a pivot point and split from there. Once we have chosen the pivot point, we put all smaller items to the left and all the larger items to the right of that.</p> <p>That means that the pivot point itself is sorted now. We continue this for left and right side recursively until we have the full list sorted.</p> <p>Choosing the pivot could be random, middle point, first, or last item of the list. There are many ways to do this each with their own pros and cons. </p> <p>Let’s see this in action to better understand the difference:</p> <p><img src="/42561febe484d44ab4fd5faf2a6d6fb6/quicksort.gif" alt="quick sort in action"></p> <div class="gatsby-code-button-container" data-toaster-id="33086144916629512000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`function quickSort(list, left, right) { let len = list.length, pivot, partitionIndex; if(left < right) { pivot = right; partitionIndex = partition(list, pivot, left, right); //sort left and right quickSort(list, left, partitionIndex - 1); quickSort(list, partitionIndex + 1, right); } return list; } function partition(list, pivot, left, right) { let pivotValue = list[pivot], partitionIndex = left; for(let i = left; i < right; i++) { if(list[i] < pivotValue) { swap(list, i, partitionIndex); partitionIndex++; } } swap(list, right, partitionIndex); return partitionIndex; } function swap(list, i, j) { let temp = list[i]; list[i] = list[j]; list[j] = temp; } quickSort([11,8,14,3,6,2,7],0,6); //[2, 3, 6, 7, 8, 11, 14]`, `33086144916629512000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">quickSort</span><span class="token punctuation">(</span><span class="token parameter">list<span class="token punctuation">,</span> left<span class="token punctuation">,</span> right</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> len <span class="token operator">=</span> list<span class="token punctuation">.</span>length<span class="token punctuation">,</span> pivot<span class="token punctuation">,</span> partitionIndex<span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span>left <span class="token operator">&lt;</span> right<span class="token punctuation">)</span> <span class="token punctuation">{</span> pivot <span class="token operator">=</span> right<span class="token punctuation">;</span> partitionIndex <span class="token operator">=</span> <span class="token function">partition</span><span class="token punctuation">(</span>list<span class="token punctuation">,</span> pivot<span class="token punctuation">,</span> left<span class="token punctuation">,</span> right<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//sort left and right</span> <span class="token function">quickSort</span><span class="token punctuation">(</span>list<span class="token punctuation">,</span> left<span class="token punctuation">,</span> partitionIndex <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">quickSort</span><span class="token punctuation">(</span>list<span class="token punctuation">,</span> partitionIndex <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span> right<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> list<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">partition</span><span class="token punctuation">(</span><span class="token parameter">list<span class="token punctuation">,</span> pivot<span class="token punctuation">,</span> left<span class="token punctuation">,</span> right</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> pivotValue <span class="token operator">=</span> list<span class="token punctuation">[</span>pivot<span class="token punctuation">]</span><span class="token punctuation">,</span> partitionIndex <span class="token operator">=</span> left<span class="token punctuation">;</span> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> left<span class="token punctuation">;</span> i <span class="token operator">&lt;</span> right<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span><span class="token punctuation">(</span>list<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">&lt;</span> pivotValue<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">swap</span><span class="token punctuation">(</span>list<span class="token punctuation">,</span> i<span class="token punctuation">,</span> partitionIndex<span class="token punctuation">)</span><span class="token punctuation">;</span> partitionIndex<span class="token operator">++</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token function">swap</span><span class="token punctuation">(</span>list<span class="token punctuation">,</span> right<span class="token punctuation">,</span> partitionIndex<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> partitionIndex<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">swap</span><span class="token punctuation">(</span><span class="token parameter">list<span class="token punctuation">,</span> i<span class="token punctuation">,</span> j</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> temp <span class="token operator">=</span> list<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span> list<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> list<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">;</span> list<span class="token punctuation">[</span>j<span class="token punctuation">]</span> <span class="token operator">=</span> temp<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">quickSort</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">11</span><span class="token punctuation">,</span><span class="token number">8</span><span class="token punctuation">,</span><span class="token number">14</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">6</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">7</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//[2, 3, 6, 7, 8, 11, 14]</span></code></pre></div> <p>As you can see, the more efficient the algorithm gets, the more complex the implementation will be. In terms of complexity, it’s worst than merge sort in worst-case, and equal in average and best.</p> <table> <thead> <tr> <th>Case</th> <th>Complexity</th> </tr> </thead> <tbody> <tr> <td>Worst-case performance</td> <td>O(n<sup>2</sup>)</td> </tr> <tr> <td>Best-case performance</td> <td>O(n log n) with simple partition, O(n) with <a href="https://en.wikipedia.org/wiki/Quicksort">three-way partition</a></td> </tr> <tr> <td>Average-case performance</td> <td>O(n log n)</td> </tr> <tr> <td>Worst-case space</td> <td>O(n) auxiliary</td> </tr> </tbody> </table> <h2 id="heap-sort" style="position:relative;"><a href="#heap-sort" aria-label="heap sort permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Heap sort</h2> <p>Heap sort is a comparison based sort, you can think of it as an improved version of selection sort. It divides it’s input into a sorted and an unsorted region, then iteratively shrinks the unsorted region by extracting the largest item and inserting it into the sorted region.</p> <p>The unsorted region is kept in <a href="https://en.wikipedia.org/wiki/Heap_(data_structure)">heap data structure</a> to more quickly find the largest item in each step.</p> <blockquote> <p>💡 Since there is no heap data structure in JavaScript, we can use an array to represent it.</p> </blockquote> <p>That was a mouthful, so let’s see it in action:</p> <p><img src="/2d571b4de2faccf2df0c7890db0dc9b7/heapsort.gif" alt="heap sort in action"></p> <div class="gatsby-code-button-container" data-toaster-id="72278992826033136000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`function heapSort(list) { let len = list.length; let i = Math.floor(len / 2 - 1); let j = len - 1; while(i >= 0) { heapify(list, len, i); i--; } while(k >= 0) { [list[0], list[k]] = [list[k], list[0]]; heapify(list, k, 0); k--; } return list; } function heapify(list, len, i){ let largest = i; let left = i * 2 + 1; let right = left + 1; if(left < len && > list[left] > list[largest]) { largest = left; } if(right < len && list[right] > list[largest]) { largest = right; } if(largest != i) { [list[i], list[largest]] = [list[largest], list[i]]; heapify(list, len, largest); } return list; }`, `72278992826033136000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">heapSort</span><span class="token punctuation">(</span><span class="token parameter">list</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> len <span class="token operator">=</span> list<span class="token punctuation">.</span>length<span class="token punctuation">;</span> <span class="token keyword">let</span> i <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>len <span class="token operator">/</span> <span class="token number">2</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">let</span> j <span class="token operator">=</span> len <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">while</span><span class="token punctuation">(</span>i <span class="token operator">>=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">heapify</span><span class="token punctuation">(</span>list<span class="token punctuation">,</span> len<span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">;</span> i<span class="token operator">--</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">while</span><span class="token punctuation">(</span>k <span class="token operator">>=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span>list<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> list<span class="token punctuation">[</span>k<span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span>list<span class="token punctuation">[</span>k<span class="token punctuation">]</span><span class="token punctuation">,</span> list<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token function">heapify</span><span class="token punctuation">(</span>list<span class="token punctuation">,</span> k<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> k<span class="token operator">--</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> list<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">heapify</span><span class="token punctuation">(</span><span class="token parameter">list<span class="token punctuation">,</span> len<span class="token punctuation">,</span> i</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">let</span> largest <span class="token operator">=</span> i<span class="token punctuation">;</span> <span class="token keyword">let</span> left <span class="token operator">=</span> i <span class="token operator">*</span> <span class="token number">2</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">let</span> right <span class="token operator">=</span> left <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span>left <span class="token operator">&lt;</span> len <span class="token operator">&amp;&amp;</span> <span class="token operator">></span> list<span class="token punctuation">[</span>left<span class="token punctuation">]</span> <span class="token operator">></span> list<span class="token punctuation">[</span>largest<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> largest <span class="token operator">=</span> left<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span><span class="token punctuation">(</span>right <span class="token operator">&lt;</span> len <span class="token operator">&amp;&amp;</span> list<span class="token punctuation">[</span>right<span class="token punctuation">]</span> <span class="token operator">></span> list<span class="token punctuation">[</span>largest<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> largest <span class="token operator">=</span> right<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span><span class="token punctuation">(</span>largest <span class="token operator">!=</span> i<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span>list<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span> list<span class="token punctuation">[</span>largest<span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span>list<span class="token punctuation">[</span>largest<span class="token punctuation">]</span><span class="token punctuation">,</span> list<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token function">heapify</span><span class="token punctuation">(</span>list<span class="token punctuation">,</span> len<span class="token punctuation">,</span> largest<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> list<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div> <p>In the above code snippet, <code class="language-text">heapify</code> function compares three elements, the parent, and two children. It then makes sure that they are in the correct order for a <strong>max heap</strong> since we’re building the heap from bottom up.</p> <table> <thead> <tr> <th>Case</th> <th>Complexity</th> </tr> </thead> <tbody> <tr> <td>Worst-case performance</td> <td>O(n log n)</td> </tr> <tr> <td>Best-case performance</td> <td>O(n log n) distinct keys, O(n) with equal keys</td> </tr> <tr> <td>Average-case performance</td> <td>O(n log n)</td> </tr> <tr> <td>Worst-case space</td> <td>O(n) total, O(1) auxiliary</td> </tr> </tbody> </table> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>You should have a good understanding of these sort algorithms by now. If not, I recommend going through them again and try to write a few examples with a pen and paper. Don’t worry if you have trouble understanding the more complex ones like heap sort. It’s completely OK as I had the same trouble initially. But with practice and trying to implement them I learnt them at the end.</p> <p>There are many other sort algorithms out there, so feel free to explore them and compare the way they work with what you’ve learnt so far.</p> <p>Thanks for reading and enjoy sorting your collections.</p> <blockquote> <p>⚡ All the images in this post are pulled from the algorithm’s Wikipedia pages.</p> </blockquote><![CDATA[Have you ever thought about for loops? ➰]]>https://yashints.dev/blog/2020/04/24/iteratorshttps://yashints.dev/blog/2020/04/24/iteratorsFri, 24 Apr 2020 00:00:00 GMT<p> Using a loop is almost a must in our day to day life. But have you ever thought what kind of loop should you use? Do you know the difference between enumerables and iterables? This article sheds some light in this space, so read on if you’re interested.</p> <!--more--> <h2 id="background" style="position:relative;"><a href="#background" aria-label="background permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Background</h2> <p>Looping has seen quite a few changes from when I started programming. I remember using while loops and thinking wow, this is cool (I was printing starts on console using MS-DOS).</p> <p>For loop is another way to iterate through a data structure which contains many items. But non of these methods iterate over the actual structure. They use a sequence, usually named <code class="language-text">i</code> which mirrors the identifier for you.</p> <div class="gatsby-code-button-container" data-toaster-id="85737420209108800000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const fruits = ['🍉', '🍎', '🍌']; for (let i = 0; i < fruits.length; i++) { console.log(fruits[i]); } // 🍉, 🍎, 🍌`, `85737420209108800000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> fruits <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'🍉'</span><span class="token punctuation">,</span> <span class="token string">'🍎'</span><span class="token punctuation">,</span> <span class="token string">'🍌'</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> fruits<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>fruits<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// 🍉, 🍎, 🍌</span></code></pre></div> <p>Here <code class="language-text">i</code> is an index which allows you to access the elements of fruits array and is not part of the array itself. But with progress on <strong>JavaScript</strong> towards more modern ways of programming, things have changes now. We have <code class="language-text">for...in</code>, and <code class="language-text">for...of</code> loops which use a different mechanism for going through items in a collection.</p> <h2 id="concepts" style="position:relative;"><a href="#concepts" aria-label="concepts permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Concepts</h2> <p>Before we delve into these newer ways of iteration, we need to be on the same page around some concepts. So let’s go through them now:</p> <ul> <li><strong>Iterables</strong>: This is a kind of loop where we are performing a repetition. Meaning the same set of actions are performed on each item. </li> <li><strong>Enumerables</strong>: This is a kind of loop where we making mention of, or counting items one at a time. This means the collection’s elements can be distinctly identified and referenced.</li> </ul> <p>That didn’t click for me at first, but after going through some examples, it finally made sense. If you consider a <em>full pencil case</em>, that’s an enumerable. When you <em>line up at Aldi</em> to pay, that line is an iterable. A <em>wad of cash</em> is an enumerable, whereas a <em>row of keys on your keyboard</em> is an iterable.</p> <blockquote> <p>💡 In order for an object to be <code class="language-text">iterable</code>, it MUST implement an <code class="language-text">@@iterator</code> property which returns an iterator. An iterator object is one which has a <code class="language-text">next</code> method which returns the next item in the collection. That’s why an object is not an iterable.</p> </blockquote> <p>By now you should have started to see the pattern here. The best analogy I came across is:</p> <blockquote> <p>😍 <strong>Enumerables</strong> are like rectangles whereas <strong>iterables</strong> are squares. This means all <code class="language-text">iterables</code> are <code class="language-text">enumerables</code>, however, not all <code class="language-text">enumerables</code> are <code class="language-text">iterables</code>.</p> </blockquote> <h2 id="code-classlanguage-textforincode" style="position:relative;"><a href="#code-classlanguage-textforincode" aria-label="code classlanguage textforincode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="language-text">for...in</code></h2> <p>So let’s start from <code class="language-text">enumerables</code>. You can go through enumerables using <code class="language-text">for...in</code>. The use case is mainly to go through key-value pairs in an object:</p> <div class="gatsby-code-button-container" data-toaster-id="96633692875206180000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const superCar = { make: 'Lamborghini', model: 'Veneno', year: '2020' }; for (let key in superCar) { console.log(\`\${key} --> \${superCar[key]}\`); } // make --> Lamborghini // model --> Veneno // year --> 2020`, `96633692875206180000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> superCar <span class="token operator">=</span> <span class="token punctuation">{</span> make<span class="token operator">:</span> <span class="token string">'Lamborghini'</span><span class="token punctuation">,</span> model<span class="token operator">:</span> <span class="token string">'Veneno'</span><span class="token punctuation">,</span> year<span class="token operator">:</span> <span class="token string">'2020'</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> key <span class="token keyword">in</span> superCar<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>key<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> --> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>superCar<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// make --> Lamborghini</span> <span class="token comment">// model --> Veneno</span> <span class="token comment">// year --> 2020</span></code></pre></div> <p>You can also use <code class="language-text">for...in</code> to go through index values of an iterable like an array or a string:</p> <div class="gatsby-code-button-container" data-toaster-id="35534885444627420000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`let fact = 'Lamborghini is the best!'; for (let index in fact) { console.log(\`Index of \${fact[index]}: \${index}\`); } // Index of L: 0 // Index of a: 1 // Index of m: 2 // Index of b: 3 // ...`, `35534885444627420000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">let</span> fact <span class="token operator">=</span> <span class="token string">'Lamborghini is the best!'</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> index <span class="token keyword">in</span> fact<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Index of </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>fact<span class="token punctuation">[</span>index<span class="token punctuation">]</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>index<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// Index of L: 0</span> <span class="token comment">// Index of a: 1</span> <span class="token comment">// Index of m: 2</span> <span class="token comment">// Index of b: 3</span> <span class="token comment">// ...</span></code></pre></div> <blockquote> <p>💡 Beware that you can’t iterate on <code class="language-text">Symbol</code> properties with <code class="language-text">for...in</code> and that’s because <code class="language-text">Symbols</code> are primitive data types that are <em>always</em> unique. They are generally used as private properties to avoid name clashes when inheritance is used.</p> </blockquote> <h2 id="using-code-classlanguage-textforofcode" style="position:relative;"><a href="#using-code-classlanguage-textforofcode" aria-label="using code classlanguage textforofcode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Using <code class="language-text">for...of</code></h2> <p>This kind of loop is applicable to “iterable objects” meaning the item after <code class="language-text">of</code> MUST be an <code class="language-text">iterable</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="21774099481461805000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const fruits = ['🍉', '🍎', '🍌']; for (let fruit of fruits) { console.log(\`\${fruit} is delicious.\`); } // 🍉 is delicious. // 🍎 is delicious. // 🍌 is delicious.`, `21774099481461805000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> fruits <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'🍉'</span><span class="token punctuation">,</span> <span class="token string">'🍎'</span><span class="token punctuation">,</span> <span class="token string">'🍌'</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> fruit <span class="token keyword">of</span> fruits<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>fruit<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> is delicious.</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// 🍉 is delicious.</span> <span class="token comment">// 🍎 is delicious.</span> <span class="token comment">// 🍌 is delicious.</span></code></pre></div> <p>And again we can use it on strings, but with a slight difference:</p> <div class="gatsby-code-button-container" data-toaster-id="28643398547430322000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`let fact = 'Yas'; for (let char of fact) { console.log(char); } // Y // a // s`, `28643398547430322000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">let</span> fact <span class="token operator">=</span> <span class="token string">'Yas'</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> char <span class="token keyword">of</span> fact<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>char<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// Y</span> <span class="token comment">// a</span> <span class="token comment">// s</span></code></pre></div> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>We saw the difference between these two modern ways of looping through collections, let’s make more informed decisions as to use what where and write cleaner, more readable code 👊🏽.</p><![CDATA[Stay on top of performance with Lighthouse CI 🚦]]>https://yashints.dev/blog/2020/04/13/lighthouse-cihttps://yashints.dev/blog/2020/04/13/lighthouse-ciMon, 13 Apr 2020 00:00:00 GMT<p> You’ve spent many hours trying to improve your web performance and have got it to a good speed. What happens next? How do you ensure it remains in good shape especially if you’re working in a team with diverse backgrounds and level of coding.</p> <!--more--> <h2 id="web-performance-must-be-monitored" style="position:relative;"><a href="#web-performance-must-be-monitored" aria-label="web performance must be monitored permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Web performance must be monitored</h2> <p>I truly believe web performance shouldn’t be an item in your backlog, rather part of acceptance criteria on each story. That said, having discipline is hard when it comes to web performance. Each member of the team should be aware of dos and don’ts so that they can right code which doesn’t add a few seconds to current page load time, or user’s interactivity with the page.</p> <p>In order to do so, you need to constantly monitor the performance of your application and when is a better time to do it than your CI/CD pipeline or when creating a pull request to get the code merged in (it’s worth mentioning having a CI/CD pipeline is not necessary to have a high quality, well written and performing site).</p> <p>In addition to all of that, your site performs differently from your localhost, so you need to ensure you’re testing close to your actual environment.</p> <h2 id="lighthouse-ci" style="position:relative;"><a href="#lighthouse-ci" aria-label="lighthouse ci permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Lighthouse CI</h2> <p><a href="https://github.com/GoogleChrome/lighthouse-ci">Lighthouse CI</a> is a set of commands that make continuously running, asserting, saving, and retrieving Lighthouse results as easy as possible.</p> <p>This is a great tool which allows you to run audits on your code base using command line, and raise an alert when someone unintentionally downgrades the performance.</p> <h2 id="what-to-measure" style="position:relative;"><a href="#what-to-measure" aria-label="what to measure permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>What to measure?</h2> <p>There are countless metrics on which we could focus on. Some are user centric like time to interact, some are resource centric such as the size of your <em>JavaScript</em> or <em>CSS</em> files. Lighthouse CI allows us to easily focus on the size of the files. You can create two types of budgets:</p> <p>1- <strong>Number of given resource</strong>: This will help you to for example enforce having only <code class="language-text">3</code> <em>JavaScript</em> and <code class="language-text">1</code> <em>CSS</em> file. 2- <strong>Size of a given resource</strong>: This budget will enforce that a given resource is of certain size, e.g. only <code class="language-text">500kb</code>.</p> <h2 id="how-does-it-know" style="position:relative;"><a href="#how-does-it-know" aria-label="how does it know permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>How does it know?</h2> <p>You’re probably wondering how does <strong>Lighthouse CI</strong> know what to measure and when to raise an alert. This **||is done via a <code class="language-text">JSON</code> file which is usually named <code class="language-text">budget.json</code>, but you can choose any name you prefer. </p> <h2 id="performance-budget" style="position:relative;"><a href="#performance-budget" aria-label="performance budget permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Performance budget</h2> <p>The content of this file is an array of objects representing the budgets for a path. The content will look like below if you only have one path to assert:</p> <div class="gatsby-code-button-container" data-toaster-id="56975275390036900000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`[ { &quot;resourceSizes&quot;: [ ... ], &quot;resourceCounts&quot;: [ ... ] } ]`, `56975275390036900000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"resourceSizes"</span><span class="token operator">:</span> <span class="token punctuation">[</span> ... <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"resourceCounts"</span><span class="token operator">:</span> <span class="token punctuation">[</span> ... <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span></code></pre></div> <p>Within the <code class="language-text">resourceSizes</code> and <code class="language-text">resourceCounts</code> arrays, you can add individual objects that specify the <code class="language-text">resourceType</code> and its budget. The budget can be any positive integer and the <code class="language-text">resourceType</code> can be any of the following:</p> <table> <thead> <tr> <th><strong>Resource type</strong></th> <th><strong>Description</strong></th> </tr> </thead> <tbody> <tr> <td><strong>script</strong></td> <td>JavaScript files</td> </tr> <tr> <td><strong>document</strong></td> <td>HTML documents</td> </tr> <tr> <td><strong>image</strong></td> <td>Images</td> </tr> <tr> <td><strong>stylesheet</strong></td> <td>CSS files</td> </tr> <tr> <td><strong>font</strong></td> <td>Webfonts</td> </tr> <tr> <td><strong>media</strong></td> <td>Other media</td> </tr> <tr> <td><strong>other</strong></td> <td>Any other resource which doesn’t match the above, e.g. data transfers over Websocket connections</td> </tr> <tr> <td><strong>third-party</strong></td> <td>All resources from a third-party domain</td> </tr> <tr> <td><strong>total</strong></td> <td>All resources combined</td> </tr> </tbody> </table> <p>For example, the following file will set a 200Kb budget for all scripts, a 500Kb for all images, and a 500Kb for all other resources. Then it sets the total network requests to be 25.</p> <div class="gatsby-code-button-container" data-toaster-id="64066724610815150000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`[ { &quot;resourceSizes&quot;: [ { &quot;resourceType&quot;: &quot;script&quot;, &quot;budget&quot;: 200 }, { &quot;resourceType&quot;: &quot;image&quot;, &quot;budget&quot;: 500 }, { &quot;resourceType&quot;: &quot;total&quot;, &quot;budget&quot;: 500 } ], &quot;resourceCounts&quot;: [ { &quot;resourceType&quot;: &quot;total&quot;, &quot;budget&quot;: 25 } ] } ]`, `64066724610815150000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"resourceSizes"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"resourceType"</span><span class="token operator">:</span> <span class="token string">"script"</span><span class="token punctuation">,</span> <span class="token property">"budget"</span><span class="token operator">:</span> <span class="token number">200</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">"resourceType"</span><span class="token operator">:</span> <span class="token string">"image"</span><span class="token punctuation">,</span> <span class="token property">"budget"</span><span class="token operator">:</span> <span class="token number">500</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">"resourceType"</span><span class="token operator">:</span> <span class="token string">"total"</span><span class="token punctuation">,</span> <span class="token property">"budget"</span><span class="token operator">:</span> <span class="token number">500</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"resourceCounts"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"resourceType"</span><span class="token operator">:</span> <span class="token string">"total"</span><span class="token punctuation">,</span> <span class="token property">"budget"</span><span class="token operator">:</span> <span class="token number">25</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span></code></pre></div> <p>As of <strong>Lighthouse</strong> 5.3 you can add a <code class="language-text">path</code> property to select which pages the budget should apply to. This is very handy because it allows you to have a centralised budget file for all your pages.</p> <div class="gatsby-code-button-container" data-toaster-id="29918470807195010000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`[ { &quot;path&quot;:&quot;/*&quot;, &quot;resourceSizes&quot;: [ ... ], &quot;resourceCounts&quot;: [ ... ] }, { &quot;path&quot;:&quot;/blog&quot;, &quot;resourceSizes&quot;: [ ... ], &quot;resourceCounts&quot;: [ ... ] }, { &quot;path&quot;:&quot;/contact&quot;, &quot;resourceSizes&quot;: [ ... ], &quot;resourceCounts&quot;: [ ... ] } ]`, `29918470807195010000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"path"</span><span class="token operator">:</span><span class="token string">"/*"</span><span class="token punctuation">,</span> <span class="token property">"resourceSizes"</span><span class="token operator">:</span> <span class="token punctuation">[</span> ... <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"resourceCounts"</span><span class="token operator">:</span> <span class="token punctuation">[</span> ... <span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">"path"</span><span class="token operator">:</span><span class="token string">"/blog"</span><span class="token punctuation">,</span> <span class="token property">"resourceSizes"</span><span class="token operator">:</span> <span class="token punctuation">[</span> ... <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"resourceCounts"</span><span class="token operator">:</span> <span class="token punctuation">[</span> ... <span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">"path"</span><span class="token operator">:</span><span class="token string">"/contact"</span><span class="token punctuation">,</span> <span class="token property">"resourceSizes"</span><span class="token operator">:</span> <span class="token punctuation">[</span> ... <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"resourceCounts"</span><span class="token operator">:</span> <span class="token punctuation">[</span> ... <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span></code></pre></div> <h2 id="how-should-you-choose-your-numbers" style="position:relative;"><a href="#how-should-you-choose-your-numbers" aria-label="how should you choose your numbers permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>How should you choose your numbers?</h2> <p>Finding the performance budget is not an easy task since it will depend on your application’s structure and bundling style. However, you can use this useful tool called <a href="https://perf-budget-calculator.firebaseapp.com/"><strong>Performance Budget Calculator</strong></a> to have a starting point. You might have to run the tool multiple time to each to a point where you’d be happy with the result. You don’t want to be too aggressive and also too complacent either.</p> <h2 id="using-the-ci-locally" style="position:relative;"><a href="#using-the-ci-locally" aria-label="using the ci locally permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Using the CI locally</h2> <p>You can install the CI locally with:</p> <div class="gatsby-code-button-container" data-toaster-id="16398948384899992000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`npm install -g @lhci/cli`, `16398948384899992000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> -g @lhci/cli</code></pre></div> <p>It also has a dashboard which shows you the historical runs, compares reports and store their results.</p> <div class="gatsby-code-button-container" data-toaster-id="5947199033042394000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`npm install @lhci/server`, `5947199033042394000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> @lhci/server</code></pre></div> <p>Before running the CI, you need to have a configuration file to tell the tool what to test and where to find the budget file (you could also pass those individually without a config file, but it’d be a pain):</p> <div class="gatsby-code-button-container" data-toaster-id="76952280237165500000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`// lighthouserc.json { &quot;ci&quot;: { &quot;collect&quot;: { &quot;numberOfRuns&quot;: 2, &quot;startServerCommand&quot;: &quot;yarn serve&quot;, &quot;url&quot;: &quot;http://localhost:8080&quot; }, &quot;preset&quot;: &quot;lighthouse:recommended&quot; } }`, `76952280237165500000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token comment">// lighthouserc.json</span> <span class="token punctuation">{</span> <span class="token property">"ci"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"collect"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"numberOfRuns"</span><span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token property">"startServerCommand"</span><span class="token operator">:</span> <span class="token string">"yarn serve"</span><span class="token punctuation">,</span> <span class="token property">"url"</span><span class="token operator">:</span> <span class="token string">"http://localhost:8080"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"preset"</span><span class="token operator">:</span> <span class="token string">"lighthouse:recommended"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div> <p>Then you can run the tool on your local web server by first running:</p> <div class="gatsby-code-button-container" data-toaster-id="84041707291725960000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`lhci autorun --config=./lighthouserc.json`, `84041707291725960000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">lhci autorun --config<span class="token operator">=</span>./lighthouserc.json</code></pre></div> <p>and then:</p> <div class="gatsby-code-button-container" data-toaster-id="95592323223025370000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`lhci assert --no-lighthouserc --budgetsFile=budget.json`, `95592323223025370000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">lhci assert --no-lighthouserc --budgetsFile<span class="token operator">=</span>budget.json</code></pre></div> <p>And you will get a result similar to below based on your app’s performance:</p> <div class="gatsby-code-button-container" data-toaster-id="79713375550854630000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`2 result(s) for http://localhost:8080/ × resource-summary.script.size failure for maxNumericValue assertion Keep request counts low and transfer sizes small Documentation: https://developers.google.com/web/tools/lighthouse/audits/budgets expected: <=102400 found: 2416174 all values: 2416174, 2416174 × resource-summary.total.size failure for maxNumericValue assertion Keep request counts low and transfer sizes small Documentation: https://developers.google.com/web/tools/lighthouse/audits/budgets expected: <=512000 found: 2437694 all values: 2437694, 2437694 Assertion failed. Exiting with status code 1.`, `79713375550854630000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash"><span class="token number">2</span> result<span class="token punctuation">(</span>s<span class="token punctuation">)</span> <span class="token keyword">for</span> http://localhost:8080/ × resource-summary.script.size failure <span class="token keyword">for</span> maxNumericValue assertion Keep request counts low and transfer sizes small Documentation: https://developers.google.com/web/tools/lighthouse/audits/budgets expected: <span class="token operator">&lt;</span><span class="token operator">=</span><span class="token number">102400</span> found: <span class="token number">2416174</span> all values: <span class="token number">2416174</span>, <span class="token number">2416174</span> × resource-summary.total.size failure <span class="token keyword">for</span> maxNumericValue assertion Keep request counts low and transfer sizes small Documentation: https://developers.google.com/web/tools/lighthouse/audits/budgets expected: <span class="token operator">&lt;</span><span class="token operator">=</span><span class="token number">512000</span> found: <span class="token number">2437694</span> all values: <span class="token number">2437694</span>, <span class="token number">2437694</span> Assertion failed. Exiting with status code <span class="token number">1</span>.</code></pre></div> <h2 id="using-the-tool-on-your-prs" style="position:relative;"><a href="#using-the-tool-on-your-prs" aria-label="using the tool on your prs permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Using the tool on your PRs</h2> <p>I am focusing on <a href="https://github.com/features/actions">GitHub</a> using actions here. But you can apply this technique to <a href="https://azure.microsoft.com/en-au/services/devops/">Azure DevOps</a>, <a href="https://circleci.com/">CircleCI</a>, <a href="https://www.jetbrains.com/teamcity/">TeamCity</a>, or any other tool you’re using. For this to work you will need to have a <a href="https://guides.github.com/introduction/flow/">GitHub flow</a> in your <code class="language-text">git</code> repository defined.</p> <p>This article’s focus is not to teach you how to create a workflow, but here is the bare minimum you will need to have. Create a <code class="language-text">.yaml</code>/<code class="language-text">.yml</code> file in the <code class="language-text">.github/workflows</code> folder, you can name it whatever you want. I usually name them after what’s their purpose, e.g. <code class="language-text">lighthouse.yml</code> or <code class="language-text">lhci-performance-bot.yml</code>.</p> <p>But before we get to the content of our <code class="language-text">yaml</code> file, let’s see what we need to do on each PR:</p> <ol> <li>Pull down the code</li> <li>Build the app</li> <li>Deploy to a temporary site (I am using Netlify Preview here, but you can use others like staging slots on Azure App Service, etc)</li> <li>Run Lighthouse CI on the site</li> <li>Fail if the conditions are not met</li> </ol> <p>For this to work, we need an application. So I just spun up a new <a href="https://vuejs.org/">Vue</a> application using <a href="https://cli.vuejs.org/">Vue CLI</a>, then added my workflow to it and pushed it to <a href="https://github.com/yashints/lighthouse-ci-pr-action">a new GitHub repo</a>.</p> <p>Here is how my workflow looks like:</p> <div class="gatsby-code-button-container" data-toaster-id="1508309465443269400" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`name: Lighthouse CI on: pull_request: branches: [master] jobs: lighthouse: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Setup Node 12 uses: actions/setup-node@v1 with: node-version: 12.x - name: Yarn Install and Build run: | yarn yarn build - name: Waiting for 200 from the Netlify Preview uses: jakepartusch/wait-for-netlify-action@v1 id: waitFor200 with: site_name: &quot;lighthouse-ci-pr&quot; - name: Audit URLs using Lighthouse uses: treosh/lighthouse-ci-action@v2 with: urls: | \$DEPLOY_URL/ \$DEPLOY_URL/about runs: 3 budgetPath: ./budget.json env: DEPLOY_URL: \${{ steps.waitFor200.outputs.url }}`, `1508309465443269400`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="yml"><pre class="language-yml"><code class="language-yml">name: Lighthouse CI on: pull_request: branches: [master] jobs: lighthouse: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Setup Node 12 uses: actions/setup-node@v1 with: node-version: 12.x - name: Yarn Install and Build run: | yarn yarn build - name: Waiting for 200 from the Netlify Preview uses: jakepartusch/wait-for-netlify-action@v1 id: waitFor200 with: site_name: &quot;lighthouse-ci-pr&quot; - name: Audit URLs using Lighthouse uses: treosh/lighthouse-ci-action@v2 with: urls: | $DEPLOY_URL/ $DEPLOY_URL/about runs: 3 budgetPath: ./budget.json env: DEPLOY_URL: ${{ steps.waitFor200.outputs.url }}</code></pre></div> <p>What is happening is that I am just creating an action on each PR. In this action, we need to pull down the code, install node, run <code class="language-text">yarn</code> and <code class="language-text">yarn build</code> to build the application, wait for Netlify to deploy our PR into a preview site, then get the URL and inject it into the next step.</p> <p>I’m just using <a href="https://github.com/marketplace/actions/wait-for-netlify"><code class="language-text">wait-for-netlify-action</code></a>, but it’s not that hard to implement this part. Then we will be using the <a href="https://github.com/treosh/lighthouse-ci-action/"><code class="language-text">lighthouse-ci-action</code></a> to run our audit on the paths we have specified.</p> <p>Notice I am not using a <strong>Lighthouse</strong> configuration file in this workflow because it’s not needed. You can pass the parameters directly to the action like I’ve done above. I am just auditing the home and about pages since I’ve only got these two pages.</p> <p>You can pass as many URL’s to this as you like, but if there are many of the, it makes more sense to add the config file back.</p> <blockquote> <p>💡 Remember to setup Netlify for your site and set it to create a deployment for every PR. Then get the site id and pass it to the <code class="language-text">wait-for-netlify-action</code> action.</p> </blockquote> <p><strong>Pro tip</strong>: When you setup your Vue CLI generated application which is using Vue Router, the non default routes won’t work if the user types them in the browser URL bar and hits enter. That’s because that route is handled on the client side and server doesn’t know about it. To fix that you need to add a URL rewrite rule to return your <code class="language-text">index.html</code> for all legitimate routes.</p> <p>In case of Netlify, just create a file named <code class="language-text">_redirects</code> inside your <em>public</em> and add the following line to it.</p> <div class="gatsby-code-button-container" data-toaster-id="87795307583439850000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`/* /index.html 200`, `87795307583439850000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">/* /index.html <span class="token number">200</span></code></pre></div> <h2 id="result" style="position:relative;"><a href="#result" aria-label="result permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Result</h2> <p>I created a branch and pushed it up. Then created a PR and voila, the action kicked in and failed, since I have a large image on the about page.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1080px; " > <a class="gatsby-resp-image-link" href="/static/6d8fde67ffb5d7e17f0cfe9e2c0d8100/4e663/ci-results.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 44.074074074074076%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAJABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAMFBP/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHVHrQUeID/xAAcEAABAwUAAAAAAAAAAAAAAAACAAMTAQQFEDL/2gAIAQEAAQUCvKkAzOqZxZDjX//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABsQAAEEAwAAAAAAAAAAAAAAAAIAATOREBJx/9oACAEBAAY/Ah1J2UhWpCtB3P8A/8QAGRAAAgMBAAAAAAAAAAAAAAAAARAhMaGx/9oACAEBAAE/IZxYmixa0OP/2gAMAwEAAgADAAAAECw//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAGxABAAEFAQAAAAAAAAAAAAAAAQARICExkWH/2gAIAQEAAT8QbnjOCuPKRHfbFd9tgH//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="PR validation failed on GitHub action using lighthouse CI&#39;s audit" title="PR validation failed on GitHub action using lighthouse CI&#39;s audit" src="/static/6d8fde67ffb5d7e17f0cfe9e2c0d8100/47311/ci-results.jpg" srcset="/static/6d8fde67ffb5d7e17f0cfe9e2c0d8100/6f81f/ci-results.jpg 270w, /static/6d8fde67ffb5d7e17f0cfe9e2c0d8100/09d21/ci-results.jpg 540w, /static/6d8fde67ffb5d7e17f0cfe9e2c0d8100/47311/ci-results.jpg 1080w, /static/6d8fde67ffb5d7e17f0cfe9e2c0d8100/0047d/ci-results.jpg 1620w, /static/6d8fde67ffb5d7e17f0cfe9e2c0d8100/4e663/ci-results.jpg 1893w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <p>I then reduced the size of the image and pushed the changes up. This time it passed.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1080px; " > <a class="gatsby-resp-image-link" href="/static/63e3628409b060661f7e8007c50a4a98/98d66/auditsuccess.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 41.11111111111111%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAIABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAEEBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAG5liSD/8QAGBAAAwEBAAAAAAAAAAAAAAAAAAIDFAT/2gAIAQEAAQUC6qPJdljZY//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABsQAAICAwEAAAAAAAAAAAAAAAABMpECEjFh/9oACAEBAAY/AsdX3wkqJKj/xAAXEAEBAQEAAAAAAAAAAAAAAAABAPER/9oACAEBAAE/IXwTpmIsRf/aAAwDAQACAAMAAAAQ/D//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAZEAEAAgMAAAAAAAAAAAAAAAABEWEAEDH/2gAIAQEAAT8QdHAVlwudVUGX/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="PR validation passing on GitHub action using lighthouse CI" title="PR validation passing on GitHub action using lighthouse CI" src="/static/63e3628409b060661f7e8007c50a4a98/47311/auditsuccess.jpg" srcset="/static/63e3628409b060661f7e8007c50a4a98/6f81f/auditsuccess.jpg 270w, /static/63e3628409b060661f7e8007c50a4a98/09d21/auditsuccess.jpg 540w, /static/63e3628409b060661f7e8007c50a4a98/47311/auditsuccess.jpg 1080w, /static/63e3628409b060661f7e8007c50a4a98/0047d/auditsuccess.jpg 1620w, /static/63e3628409b060661f7e8007c50a4a98/98d66/auditsuccess.jpg 1905w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>We learned together how to use Lighthouse CI, a tool which allows you to run audits on your sites from command line in our CI/CD pipeline to make sure no one is downgrading the performance when they work on the application.</p> <p>This way, we’re always on top of our game rather than creating backlog items to find the issues and fix them later.</p> <p>In addition to that, your users are going to be happy and remain happy with their experience which is worth all the effort.</p> <p>Hope you’ve enjoyed reading this and happy performance enforcement 👋🏽.</p><![CDATA[How I recovered a day's worth of work with git 🏥]]>https://yashints.dev/blog/2020/04/05/git-logshttps://yashints.dev/blog/2020/04/05/git-logsSun, 05 Apr 2020 00:00:00 GMT<p> I was working on a project a week ago and had a local branch (with a few commits) I was going to push to upstream to create a PR (pull request). However, after pulling down master and rebasing, I realised all of my code except my first commit is gone after rebase 😱.</p> <!--more--> <h2 id="background" style="position:relative;"><a href="#background" aria-label="background permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Background</h2> <p>I had a local branch which I was working on. Since I’d made a few changes before end of the day, I committed those and went about to do some parenting.</p> <p>The day after that, I restarted my work and had many other changes in a few other commits by the time I was ready to push my code to upstream. But before we do it, it’s our practice to pull down master and rebase in case there is any conflict, or changes made by someone else has had any side effects on the bit we’ve done.</p> <h2 id="rebase" style="position:relative;"><a href="#rebase" aria-label="rebase permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Rebase</h2> <p>So I pulled down the master branch and rebased it directly from origin using (don’t do this at home please, I’ll explain later):</p> <div class="gatsby-code-button-container" data-toaster-id="76755439312908980000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`git pull origin master --rebase`, `76755439312908980000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre class="language-powershell"><code class="language-powershell">git pull origin master <span class="token operator">--</span>rebase</code></pre></div> <p>Once done, I realised I had some conflicts since someone else had worked on one of the files I’d modified. So I started the merge conflict process and made sure all was good. However, I didn’t realised that when I tested the web application, the latest code wasn’t refreshed, and I was seeing my own code (don’t ask me why, it’s an old code base and you need to rebuild and hard refresh every time you make a change).</p> <p>Having seen all is good I created a PR and went for lunch. One of colleagues then reviewed the PR and since all my changes had gone apart from the small parts from yesterday’s commit, he approved and completed the PR.</p> <h2 id="someone-raised-a-bug" style="position:relative;"><a href="#someone-raised-a-bug" aria-label="someone raised a bug permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Someone raised a bug</h2> <p>I was working on something else when I realised someone has raised a bug on the feature I’d implemented and when I checked the code I was in total shock since most of my code wasn’t there anymore. So I checked my local branch and saw that’s the case, in fact several of my commits were missing from that branch altogether. </p> <p>Later I realised that I’d forgotten to add everything before committing 🤦🏽‍♂️. Just to clarify this was during a really crazy time where we were working day and night for over a week to deliver this project for all of our hospitals across Australia and New Zealand to monitor their resources in intensive care like number of available beds, ventilator, etc. I will tell you all about it once I find some time.</p> <h2 id="initial-try" style="position:relative;"><a href="#initial-try" aria-label="initial try permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Initial try</h2> <p>I started by running:</p> <div class="gatsby-code-button-container" data-toaster-id="24702905320317313000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`git reflog`, `24702905320317313000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre class="language-powershell"><code class="language-powershell">git reflog</code></pre></div> <p>I saw anything but my commits which expected because that commit command never had happened due to the files that weren’t added.</p> <h2 id="checking-stash" style="position:relative;"><a href="#checking-stash" aria-label="checking stash permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Checking stash</h2> <p>Next thing I checked was my stashed files:</p> <div class="gatsby-code-button-container" data-toaster-id="6048320606229485000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`git stash list`, `6048320606229485000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre class="language-powershell"><code class="language-powershell">git stash list</code></pre></div> <p>This showed me there were two sets of stashed files.</p> <div class="gatsby-code-button-container" data-toaster-id="70290173548814836000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`stash@{0}: WIP on elmah: 82eb0a4 Merged PR 426: Fixed pass change page stash@{1}: WIP on availability: 87b2264 Dashboard is now grouping based on hospital category, has got a filter and a search box to search for hospitals`, `70290173548814836000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre class="language-powershell"><code class="language-powershell">stash@<span class="token punctuation">{</span>0<span class="token punctuation">}</span>: WIP on elmah: 82eb0a4 Merged PR 426: Fixed pass change page stash@<span class="token punctuation">{</span>1<span class="token punctuation">}</span>: WIP on availability: 87b2264 Dashboard is now grouping based on hospital category<span class="token punctuation">,</span> has got a <span class="token keyword">filter</span> and a search box to search <span class="token keyword">for</span> hospitals</code></pre></div> <p>Then I looked into each of these with <code class="language-text">git stash show stash@{0}</code> and <code class="language-text">git stash show stash@{1}</code> but I didn’t see any of those.</p> <h2 id="checking-git-database" style="position:relative;"><a href="#checking-git-database" aria-label="checking git database permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>checking git database</h2> <p>At this point I realised that I needed some help and I contacted Scott one of our <code class="language-text">git</code> gurus to help me fine out what happened. He suggested we start by checking the database for any lost commit using:</p> <div class="gatsby-code-button-container" data-toaster-id="94921854770700000000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`git fsck --lost-found`, `94921854770700000000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre class="language-powershell"><code class="language-powershell">git fsck <span class="token operator">--</span>lost<span class="token operator">-</span>found</code></pre></div> <p>From the documentation:</p> <blockquote> <p><strong>—lost-found:</strong> Write dangling objects into .git/lost-found/commit/ or .git/lost-found/other/, depending on type. If the object is a blob, the contents are written into the file, rather than its object name.</p> </blockquote> <p>This showed me a bunch of stuff including some dangling commits.</p> <div class="gatsby-code-button-container" data-toaster-id="32881982959064950000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`Checking object directories: 100% (256/256), done. Checking objects: 100% (4282/4282), done. dangling tree 484106954fff79e5a4d7b8fd53fca05311e56e79 dangling blob d10124a92b82ccdcb1521ef814f815b75223e0f3 dangling commit 4c8288a8c30d4171c4935982e18ebd842a2c2811 dangling tree ae02e6d9b291775c9bc1eb1489ba341f8b033f48 dangling commit 2ec37c71f59766d55c09830a5b6e2c5e1c741a95 dangling blob 40c3c7ccbd197c78ceddf71c2be01b0db2114ba9 dangling tag a70363ef35f023e57e00fc625bee362c2e9e4bc9 dangling commit 1184e4a583e3d0f9cf9f3cb994a3375b16d122cd`, `32881982959064950000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre class="language-powershell"><code class="language-powershell">Checking object directories: 100<span class="token operator">%</span> <span class="token punctuation">(</span>256<span class="token operator">/</span>256<span class="token punctuation">)</span><span class="token punctuation">,</span> done<span class="token punctuation">.</span> Checking objects: 100<span class="token operator">%</span> <span class="token punctuation">(</span>4282<span class="token operator">/</span>4282<span class="token punctuation">)</span><span class="token punctuation">,</span> done<span class="token punctuation">.</span> dangling tree 484106954fff79e5a4d7b8fd53fca05311e56e79 dangling blob d10124a92b82ccdcb1521ef814f815b75223e0f3 dangling commit 4c8288a8c30d4171c4935982e18ebd842a2c2811 dangling tree ae02e6d9b291775c9bc1eb1489ba341f8b033f48 dangling commit 2ec37c71f59766d55c09830a5b6e2c5e1c741a95 dangling blob 40c3c7ccbd197c78ceddf71c2be01b0db2114ba9 dangling tag a70363ef35f023e57e00fc625bee362c2e9e4bc9 dangling commit 1184e4a583e3d0f9cf9f3cb994a3375b16d122cd</code></pre></div> <p>So we started to go through some of these to find out which one contained the files I was after.</p> <p>We checked out a few of those commits and couldn’t find what we were after. Then he suggested we check those dangling blobs which technically are a tree object containing a snapshot of everything in your current branch.</p> <h2 id="checking-git-dangling-blobs" style="position:relative;"><a href="#checking-git-dangling-blobs" aria-label="checking git dangling blobs permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Checking git dangling blobs</h2> <p>You cannot checkout those objects, instead you need to use below command where the last part is the hash code of the blob you’re looking into:</p> <div class="gatsby-code-button-container" data-toaster-id="20801749265457350000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(` git ls-tree -r d134e9e`, `20801749265457350000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre class="language-powershell"><code class="language-powershell"> git <span class="token function">ls</span><span class="token operator">-</span>tree <span class="token operator">-</span>r d134e9e</code></pre></div> <p>You can copy this from the output of the previous command and you don’t need the whole hash value, just a few from the beginning.</p> <p>The output of this command looks like this:</p> <div class="gatsby-code-button-container" data-toaster-id="61769470566367810000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`100644 blob ea25f3a9fe6094d700588f33c340d32281a7614b src/ARV.Database/ARV.Database.sqlproj.orig 100644 blob 2e47fe1d11bd2624065866591af00f80f16e5e1e src/ARV.Web.Reach/Partials/hird/incident.form.campuses.list.html 100644 blob 2a6b2547ace20f6bbda788dc4e97e4a749281185 src/ARV.Web.Reach/Scripts/app/core/filters.js 100644 blob a366e78d88695f3c1a2b5617ec03fd24387f2323 src/ARV.Web.Reach/Scripts/app/hird/incident.form.controller.js 100644 blob 461c0e11c1ad64a0bee7bb7f57ba9a99314b1510 src/Arv.Cases.External/App_Data/Arv.Cases.External.XML 100644 blob 276ace5a9dae6be5613beebedcfbf5a64f8e4c4b src/Arv.Services/Dtos/ReferenceDataDto.cs.orig 100644 blob 5336a10e14295222f28ef087643ac6696dc3cb73 src/Arv.Services/Reach/IIncidents.cs 100644 blob 6e186554f4de5347a754d39ebca1dd8867b7eb0a src/Arv.Services/Reach/Incidents.cs 100644 blob cf70ac7b4af8f9d8e89c2d84e45a23bdaf7c99de src/Arv.Services/ReferenceData.cs.orig 100644 blob 502e1286886624c6e0d46b9f65886fbc38b86bca src/Arv.Web.Core/Controllers/Reach/IncidentController.cs 100644 blob 5ef3891af8afa82dd7cdfc45058a6186e4656c34 src/Arv.Web.Core/Controllers/ReferenceController.cs 100644 blob 49e5d63ba2e59c6389c21c24b81809326711fd27 src/Arv.Web.Core/Controllers/ReferenceController.cs.orig`, `61769470566367810000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre class="language-powershell"><code class="language-powershell">100644 blob ea25f3a9fe6094d700588f33c340d32281a7614b src<span class="token operator">/</span>ARV<span class="token punctuation">.</span>Database<span class="token operator">/</span>ARV<span class="token punctuation">.</span>Database<span class="token punctuation">.</span>sqlproj<span class="token punctuation">.</span>orig 100644 blob 2e47fe1d11bd2624065866591af00f80f16e5e1e src<span class="token operator">/</span>ARV<span class="token punctuation">.</span>Web<span class="token punctuation">.</span>Reach<span class="token operator">/</span>Partials<span class="token operator">/</span>hird<span class="token operator">/</span>incident<span class="token punctuation">.</span>form<span class="token punctuation">.</span>campuses<span class="token punctuation">.</span>list<span class="token punctuation">.</span>html 100644 blob 2a6b2547ace20f6bbda788dc4e97e4a749281185 src<span class="token operator">/</span>ARV<span class="token punctuation">.</span>Web<span class="token punctuation">.</span>Reach<span class="token operator">/</span>Scripts<span class="token operator">/</span>app<span class="token operator">/</span>core<span class="token operator">/</span>filters<span class="token punctuation">.</span>js 100644 blob a366e78d88695f3c1a2b5617ec03fd24387f2323 src<span class="token operator">/</span>ARV<span class="token punctuation">.</span>Web<span class="token punctuation">.</span>Reach<span class="token operator">/</span>Scripts<span class="token operator">/</span>app<span class="token operator">/</span>hird<span class="token operator">/</span>incident<span class="token punctuation">.</span>form<span class="token punctuation">.</span>controller<span class="token punctuation">.</span>js 100644 blob 461c0e11c1ad64a0bee7bb7f57ba9a99314b1510 src<span class="token operator">/</span>Arv<span class="token punctuation">.</span>Cases<span class="token punctuation">.</span>External<span class="token operator">/</span>App_Data<span class="token operator">/</span>Arv<span class="token punctuation">.</span>Cases<span class="token punctuation">.</span>External<span class="token punctuation">.</span>XML 100644 blob 276ace5a9dae6be5613beebedcfbf5a64f8e4c4b src<span class="token operator">/</span>Arv<span class="token punctuation">.</span>Services<span class="token operator">/</span>Dtos<span class="token operator">/</span>ReferenceDataDto<span class="token punctuation">.</span>cs<span class="token punctuation">.</span>orig 100644 blob 5336a10e14295222f28ef087643ac6696dc3cb73 src<span class="token operator">/</span>Arv<span class="token punctuation">.</span>Services<span class="token operator">/</span>Reach<span class="token operator">/</span>IIncidents<span class="token punctuation">.</span>cs 100644 blob 6e186554f4de5347a754d39ebca1dd8867b7eb0a src<span class="token operator">/</span>Arv<span class="token punctuation">.</span>Services<span class="token operator">/</span>Reach<span class="token operator">/</span>Incidents<span class="token punctuation">.</span>cs 100644 blob cf70ac7b4af8f9d8e89c2d84e45a23bdaf7c99de src<span class="token operator">/</span>Arv<span class="token punctuation">.</span>Services<span class="token operator">/</span>ReferenceData<span class="token punctuation">.</span>cs<span class="token punctuation">.</span>orig 100644 blob 502e1286886624c6e0d46b9f65886fbc38b86bca src<span class="token operator">/</span>Arv<span class="token punctuation">.</span>Web<span class="token punctuation">.</span>Core<span class="token operator">/</span>Controllers<span class="token operator">/</span>Reach<span class="token operator">/</span>IncidentController<span class="token punctuation">.</span>cs 100644 blob 5ef3891af8afa82dd7cdfc45058a6186e4656c34 src<span class="token operator">/</span>Arv<span class="token punctuation">.</span>Web<span class="token punctuation">.</span>Core<span class="token operator">/</span>Controllers<span class="token operator">/</span>ReferenceController<span class="token punctuation">.</span>cs 100644 blob 49e5d63ba2e59c6389c21c24b81809326711fd27 src<span class="token operator">/</span>Arv<span class="token punctuation">.</span>Web<span class="token punctuation">.</span>Core<span class="token operator">/</span>Controllers<span class="token operator">/</span>ReferenceController<span class="token punctuation">.</span>cs<span class="token punctuation">.</span>orig</code></pre></div> <p>After checking a few of these blobs, I finally found the one which contained a version of the file close to the finishing state (yes I had to redo some of my work, but now I had to spend half an hour instead of a day).</p> <h2 id="checking-the-file" style="position:relative;"><a href="#checking-the-file" aria-label="checking the file permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Checking the file</h2> <p>Once we found the blob, we had to check what’s the content of those files. You can do that using:</p> <div class="gatsby-code-button-container" data-toaster-id="45579453566407980000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`git cat-file -p cf70ac7b`, `45579453566407980000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre class="language-powershell"><code class="language-powershell">git <span class="token function">cat</span><span class="token operator">-</span>file <span class="token operator">-</span>p cf70ac7b</code></pre></div> <p>Now you can see the content printed out to the console. But if the file is bit enough like my situation, you could just pipe this command to write it to a file like so:</p> <div class="gatsby-code-button-container" data-toaster-id="94824026166699690000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`git cat-file -p cf70ac7b | out-file temp.js`, `94824026166699690000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre class="language-powershell"><code class="language-powershell">git <span class="token function">cat</span><span class="token operator">-</span>file <span class="token operator">-</span>p cf70ac7b <span class="token punctuation">|</span> <span class="token function">out-file</span> temp<span class="token punctuation">.</span>js</code></pre></div> <p>If you’re using <em>linux</em> or <em>Mac</em>, just use your version of the equivalent.</p> <p>And that’s it, repeat this until you have all of the files you need.</p> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>A few lessons I learnt from this accident:</p> <ul> <li>Always check you have added all your files before committing (I know it sounds obvious, but it could happen to you the way it happened to me).</li> <li>Always make sure you commit your changes often after each set of critical change.</li> <li>This one has become my preference now. Rebase from your local branch and not upstream:</li> </ul> <div class="gatsby-code-button-container" data-toaster-id="56354150621642750000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`git add . git commit -m &quot;Your awesome and informative commit message&quot; git checkout master git pull git checkout feature-branch git rebase master`, `56354150621642750000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="powershell"><pre class="language-powershell"><code class="language-powershell">git add <span class="token punctuation">.</span> git commit <span class="token operator">-</span>m <span class="token string">"Your awesome and informative commit message"</span> git checkout master git pull git checkout feature<span class="token operator">-</span>branch git rebase master</code></pre></div> <ul> <li>And if you lost your code, don’t give up, <code class="language-text">git</code> is a really powerful tool.</li> </ul> <p>Hope this helps someone to save some time in case of a similar accident.</p><![CDATA[Stop using `console.log`, start using your DevTools 🛠️]]>https://yashints.dev/blog/2020/03/19/debug-devtoolshttps://yashints.dev/blog/2020/03/19/debug-devtoolsThu, 19 Mar 2020 00:00:00 GMT<p> There are many situations where we want to see what’s wrong with out code without the trouble of changing source code and push the changes again, regardless of whether we’re using local environment or production. Most folks start by writing <code class="language-text">console.log</code> statements throughout their code base and go step by step to find the place where the bug is happening. That’s OK for beginners and where you have access to source code, but what if you don’t want to waste so much time or you don’t even have access to source code?</p> <!--more--> <h2 id="devtools" style="position:relative;"><a href="#devtools" aria-label="devtools permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>DevTools</h2> <p>All major browsers have developer tools (aka DevTools) nowadays. It’s important for us web developers to know them well not just because we use them as our daily drivers to test our applications and see how they look like once deployed, but also for times when something is wrong as we want to find them efficiently.</p> <p>That’s when the DevTools comes very handy if you know the ropes. DevTools have a lot of functionalities; refer to my articles <a href="https://yashints.dev/blog/2019/01/13/chromedevtools">Chrome DevTools can do that?</a> and <a href="https://yashints.dev/blog/2019/08/08/firefox-dev-tools">FireFox DevTools can do that?</a> to have a glimpse of some of these. However, in this article we only focus on debugging experience.</p> <h2 id="the-bug" style="position:relative;"><a href="#the-bug" aria-label="the bug permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>The bug</h2> <p>In order to be able to have a common ground, we need a bug to fix. I’ve created <a href="https://glitch.com/edit/#!/debugger-demo">this demo</a> which will be working on in <a href="https://glitch.com/">Glitch</a>. In this demo, you would select a date and press the calculate age button. It will calculate your age and show it in the bottom section.</p> <p>However, there is a bug where sometimes it calculates the age by one year higher than actual. We will be looking into how to fix this.</p> <h2 id="devtoolss-debugger" style="position:relative;"><a href="#devtoolss-debugger" aria-label="devtoolss debugger permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>DevTools’s debugger</h2> <p>Both Chrome and Firefox have a debugger section we will be using in this article. I won’t go through Edge because it’s the same as Chrome. </p> <h3 id="chrome" style="position:relative;"><a href="#chrome" aria-label="chrome permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Chrome</h3> <p>You can open your DevTools in Chrome using <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>J</kbd> on Windows or <kbd>Ctrl</kbd>+<kbd>Option</kbd>+<kbd>J</kbd>.</p> <p>Once opened, navigate to the <strong>Sources</strong> tab. You will see a file navigator pane on the left where you can inspect the files that the page uses. Then there is the editor pane in the middle where you can click on the file from the navigator pane and see the content and edit them locally in the browser. And last you will see the JavaScript debugging pane where you have a set of features which you’ll learn about shortly.</p> <blockquote> <p>💡 If you resize the DevTools you might see these panes in different positions.</p> </blockquote> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1080px; " > <a class="gatsby-resp-image-link" href="/static/747a9023138d663f0ee47ceecf64bddf/c60c2/chromedevtools.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 79.62962962962963%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAQABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAwACBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAe0aiPaj/8QAFxABAQEBAAAAAAAAAAAAAAAAAQAQMf/aAAgBAQABBQJ1jt//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAUEAEAAAAAAAAAAAAAAAAAAAAg/9oACAEBAAY/Al//xAAYEAEBAQEBAAAAAAAAAAAAAAABABExIf/aAAgBAQABPyE4mQu9vG98eQYDf//aAAwDAQACAAMAAAAQow//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAZEAEBAQEBAQAAAAAAAAAAAAABEQAhMUH/2gAIAQEAAT8QlE+fW6NeMBXjutD0NNDvlOTAGo9+G//Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Chrome DevTools Sources tab" title="Chrome DevTools Sources tab" src="/static/747a9023138d663f0ee47ceecf64bddf/47311/chromedevtools.jpg" srcset="/static/747a9023138d663f0ee47ceecf64bddf/6f81f/chromedevtools.jpg 270w, /static/747a9023138d663f0ee47ceecf64bddf/09d21/chromedevtools.jpg 540w, /static/747a9023138d663f0ee47ceecf64bddf/47311/chromedevtools.jpg 1080w, /static/747a9023138d663f0ee47ceecf64bddf/c60c2/chromedevtools.jpg 1117w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <h3 id="firefox" style="position:relative;"><a href="#firefox" aria-label="firefox permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Firefox</h3> <p>In Firefox you need to use <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>I</kbd> on Windows or <kbd>Ctrl</kbd>+<kbd>Option</kbd>+<kbd>I</kbd> to open up the web developer tools.</p> <p>When opened, click on debugger tab which is very similar to what you saw before. On the left, you’ll see the navigation pane, next to it is editor pane and to the left (or below depending on how wide you’ve got your DevTools open) is the debug pane.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1080px; " > <a class="gatsby-resp-image-link" href="/static/b62cf79f3cab1f58d2a5b86faa600faa/77352/firefoxdevtools.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 52.59259259259259%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAIBAwX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAB3VsgQcX/xAAZEAACAwEAAAAAAAAAAAAAAAAAAgEREiD/2gAIAQEAAQUCzBSmV4//xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAwEBPwFX/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGBAAAgMAAAAAAAAAAAAAAAAAAAEgMUH/2gAIAQEABj8CMKUP/8QAGxAAAgIDAQAAAAAAAAAAAAAAAAERURBhkfH/2gAIAQEAAT8htSm4NXB4GIVEKj//2gAMAwEAAgADAAAAEGfP/8QAFhEAAwAAAAAAAAAAAAAAAAAAARAR/9oACAEDAQE/EKU//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAGxABAAICAwAAAAAAAAAAAAAAAQAxYZEQEUH/2gAIAQEAAT8QUFWrQWBF2UQ9dLhq6amJqf/Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Firefox DevTools debugger tab" title="Firefox DevTools debugger tab" src="/static/b62cf79f3cab1f58d2a5b86faa600faa/47311/firefoxdevtools.jpg" srcset="/static/b62cf79f3cab1f58d2a5b86faa600faa/6f81f/firefoxdevtools.jpg 270w, /static/b62cf79f3cab1f58d2a5b86faa600faa/09d21/firefoxdevtools.jpg 540w, /static/b62cf79f3cab1f58d2a5b86faa600faa/47311/firefoxdevtools.jpg 1080w, /static/b62cf79f3cab1f58d2a5b86faa600faa/0047d/firefoxdevtools.jpg 1620w, /static/b62cf79f3cab1f58d2a5b86faa600faa/77352/firefoxdevtools.jpg 1919w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <h2 id="setting-a-breakpoint" style="position:relative;"><a href="#setting-a-breakpoint" aria-label="setting a breakpoint permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Setting a breakpoint</h2> <p>When it comes to debugging, a common method is to use <code class="language-text">console.log</code> statements throughout the code base which sometimes is abused.</p> <div class="gatsby-code-button-container" data-toaster-id="10082763636426529000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const yo = document.querySelector('#yo'); function getAge() { console.log('Getting the date of birth value'); const dateString = document.querySelector('#age').value; console.log(\`date of birth is \${dateString}\`); var today = new Date(); var birthDate = new Date(dateString); var age = today.getFullYear() - birthDate.getFullYear(); console.log(\`age is \${age}\`); var m = today.getMonth() - birthDate.getMonth(); console.log(\`Birth month is \${m}\`); if (m < 0 || (m = 0 && today.getDate() < birthDate.getDate())) { console.log('The birth month is negative or is zero, we need to reduce the age by one year'); age--; console.log(\`Real age is \${age}\`); } yo.textContent = age; }`, `10082763636426529000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> yo <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'#yo'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">getAge</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Getting the date of birth value'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> dateString <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'#age'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>value<span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">date of birth is </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>dateString<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> today <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> birthDate <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span>dateString<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> age <span class="token operator">=</span> today<span class="token punctuation">.</span><span class="token function">getFullYear</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> birthDate<span class="token punctuation">.</span><span class="token function">getFullYear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">age is </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>age<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> m <span class="token operator">=</span> today<span class="token punctuation">.</span><span class="token function">getMonth</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> birthDate<span class="token punctuation">.</span><span class="token function">getMonth</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Birth month is </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>m<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>m <span class="token operator">&lt;</span> <span class="token number">0</span> <span class="token operator">||</span> <span class="token punctuation">(</span>m <span class="token operator">=</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> today<span class="token punctuation">.</span><span class="token function">getDate</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&lt;</span> birthDate<span class="token punctuation">.</span><span class="token function">getDate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'The birth month is negative or is zero, we need to reduce the age by one year'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> age<span class="token operator">--</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Real age is </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>age<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> yo<span class="token punctuation">.</span>textContent <span class="token operator">=</span> age<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div> <p>And then you look at the console to see where the bug might be. But this process is painstakingly slow which impacts your productivity a lot. So let’s see how breakpoints help us get to the point real quick.</p> <p>Breakpoints have the advantage of being in real time compared to <code class="language-text">console.log</code> statements where you need to wait for the code to get deployed and inspect the console. Apart from that, with <code class="language-text">console.log</code> statements, you need to explicitly mention which values you want to expect whereas in a breakpoint debugger shows you all of them.</p> <p>Now let’s take one step back and see how we can go about finding where to set our breakpoint to. In some cases like this you will think OK, the age is correct sometimes and not others depending on the month. So you can find your file and set your breakpoint right where the <code class="language-text">if</code> condition is.</p> <p>In some other cases where the code base might be larger, or you might be new to the team, it makes sense to follow the flow of the page. In our case user selects a date and then clicks on the calculate age button.</p> <p>The logic behind happens under that click, you the best thing for us is to set a breakpoint on the click event listener. <strong>Event Listener Breakpoints</strong> are designed for this.</p> <h3 id="chrome-1" style="position:relative;"><a href="#chrome-1" aria-label="chrome 1 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Chrome</h3> <p>In Chrome, in the debug page, click on the <strong>Event Listener Breakpoints</strong> and expand the section. Then find the <em>Mouse</em> category and select the click event.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 383px; " > <a class="gatsby-resp-image-link" href="/static/bffd8e2f8f9a2ca1a51cc884534f6f3e/411a4/chromeeventbreakpoint.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 202.22222222222223%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAoABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAIDAQX/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAH3HQdGVrJWM9AA/8QAGRAAAgMBAAAAAAAAAAAAAAAAECEAAUEg/9oACAEBAAEFAqi5Z0aP/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPwFf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPwFf/8QAFBABAAAAAAAAAAAAAAAAAAAAMP/aAAgBAQAGPwJ//8QAHRAAAgEEAwAAAAAAAAAAAAAAABEBECEx8CBBUf/aAAgBAQABPyFPRMyxG2INwZdkMvwxX//aAAwDAQACAAMAAAAQUw0wgA//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/EF//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/EF//xAAgEAABBAIBBQAAAAAAAAAAAAABABEhMRBRcWGBkaGx/9oACAEBAAE/ELZmdLcPtciik36ru+ryjwvenQMgEcputAtYaywEDOf/2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Event listener break points for mouse click in Chrome" title="Event listener break points for mouse click in Chrome" src="/static/bffd8e2f8f9a2ca1a51cc884534f6f3e/411a4/chromeeventbreakpoint.jpg" srcset="/static/bffd8e2f8f9a2ca1a51cc884534f6f3e/6f81f/chromeeventbreakpoint.jpg 270w, /static/bffd8e2f8f9a2ca1a51cc884534f6f3e/411a4/chromeeventbreakpoint.jpg 383w" sizes="(max-width: 383px) 100vw, 383px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <p>Now click on the calculate age button and DevTools will pause when the event listener executes. You might need to click on the <strong>Resume Script Execution</strong> <span class="image-inline"> <span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 26px; " > <a class="gatsby-resp-image-link" href="/static/270133261d0c3a18a5824163cb358f02/d93cc/resume-script-execution.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 76.92307692307692%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAIAAABr+ngCAAAACXBIWXMAAAsSAAALEgHS3X78AAABu0lEQVQoz42TO0sDQRDHD0QSTYykUPQDiIUi2Nr4CWystPIR8/LVKKIiohCwUbASUkuiiI8UCgpiYXwhIoKiTXyhRiRIzO3e7l3i7TgXtZGT3LIMx7G/nf/M/Fe6elBCMW1yTZtc1ea21Ld3kuXk+pEmnmlOlWWZZGSC0XRJ6yfc3glSO0htUNULiRcKQo7s86YpfflAxROcGedMeWnrjFUPClcAnAGoGxX3SQNeinNbDzj94Annjm8Yglwx4aXNM1bRL0p9YPdB7Yi4+4XdfVDig6JuqB/TZ2JaIqlonFBqDS4PAv5ERTYvuIPQOv8ZO+GZjFGF0QUrMCovy1eE3zXDYngxe3WvaKqMV2AVhWGH34jIYxUOLzRO6OFd/vRGLWV2/G7kHQGQOsDpgUicq8xyZoxYvMsPzSF945Sn0tZkfwu2e6FhXGDbkymqa4QphRqGmCtoYNUDoiuc27vkyCiUfGR+Zv7/nHuh2As2DzRN6ws7KnZIy3dYLuiwaJwXd0NlvxhazF7cMvQGo2YOM/U2Zm6Z1bfP8zoVI5u5t1HnyhFbOuTRAx47Ze9pgjN4eCWvKYrP64/OP+sLqjGZeB2UbsgAAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="resume button" title="resume button" src="/static/270133261d0c3a18a5824163cb358f02/d93cc/resume-script-execution.png" srcset="/static/270133261d0c3a18a5824163cb358f02/d93cc/resume-script-execution.png 26w" sizes="(max-width: 26px) 100vw, 26px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span> </span> if you’re using a platform like Glitch, but for your own app that won’t be needed. When the breakpoint reaches the button in your HTML, press Step into function <span class="image-inline"> <span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 18px; " > <a class="gatsby-resp-image-link" href="/static/65a9018e3c40b516ffecc298e9762b79/428de/step-into.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 144.44444444444443%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAdCAIAAAAl5NuSAAAACXBIWXMAAAsSAAALEgHS3X78AAACEUlEQVQ4y+1Uy+thcRy9/56Vn7zf5JVneRcLZedVyG6kZCULG2WhPEopimw8ig0ljzwySNSYM787ZLh+Zjs1Z3Hvt+89p3u+53zuJb4/4XQ62Ww2FosluILD4ej1+sPh8MAk/ov/GfHxeAT7crn8uAJrh8PxIDYYDA+c8/lM1Ov1XC4XjUa/XZFIJFQqFZfLvYl5PJ5cLo/H4zcO+Nlslmg2m7jpdDoajfbxCTqdDrbgT/D5/I8rwFSr1el0moDnzWZTqVRgFfZAErwGnoJjsVgKhcJqtfoVGJLY7XatVsvpdAqFwld6ch9Z1mo1UvU77d0nBoOBy+WSSCSUYpFIBHedTockU1Q1mUy8Xq9YLL5/P9bYcbvdo9HoTc/L5TIcDkulUjI2XOElEAjMZrP3QwJLi8UimUwqlUoGg4GS0M2zklpMhjGfzzOZjMfjSaVS0+n0ebxeigFMHs7f7XbH4zHWlBxqMZxDQI4hgDUZ71+dGSb7/X6pVMrn88ViEfXs9/tnPbW40WiEQiGFQoF5QmA+nw+Dsd1u34uHw6HZbGYymfg20DCqYrPZGP5er/dGjNfGYrFbybchQdXwgq/g3jzxoATsdvttku9hNBrX6/UbsdVqpRTjZ/KVmNRHIhGYfLCN2UZsX9kmgWJMJtMtMFzxS9JoNO12+yFw6qqq1WowGIRPmUym1Wr9fn+5XH6u6ifkg/drvJzHiAAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Step into function button" title="Step into function button" src="/static/65a9018e3c40b516ffecc298e9762b79/428de/step-into.png" srcset="/static/65a9018e3c40b516ffecc298e9762b79/428de/step-into.png 18w" sizes="(max-width: 18px) 100vw, 18px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span> </span> and you’ll end up in our <code class="language-text">getAge</code> function. Once you’ve stepped into the function you wanted, you can go one line at a time by clicking on the step over button or pressing <kbd>F10</kbd>.</p> <p><img src="/2f49357f26e80756caa7edb7cdf77fbc/breakpointchrome.gif" alt="Mouse click breakpoint in Chrome"></p> <h3 id="firefox-1" style="position:relative;"><a href="#firefox-1" aria-label="firefox 1 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Firefox</h3> <p>You can use the same approach to enable a mouse click event listener breakpoint in Firefox, simply expand the <strong>Event Listener Breakpoints</strong> section in the debugger pane, then expand Mouse and select the click event.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; " > <a class="gatsby-resp-image-link" href="/static/a06ab13b3e8c1d082551f8bd5a632a91/b4294/firefox-mouseclickbreakpoint.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 132.5925925925926%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAbABQDASIAAhEBAxEB/8QAGQAAAwADAAAAAAAAAAAAAAAAAAIDAQQF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB7bq5AwFaI5rAH//EABsQAAEFAQEAAAAAAAAAAAAAADEAAQIDECFC/9oACAEBAAEFAsk/csLFWH0pn//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQMBAT8BH//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BH//EABQQAQAAAAAAAAAAAAAAAAAAADD/2gAIAQEABj8CT//EABoQAAIDAQEAAAAAAAAAAAAAAAARARAhsTH/2gAIAQEAAT8he1FAhPUI4nptcbcz/9oADAMBAAIAAwAAABADGA3/xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/EB//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/EB//xAAgEAEAAgICAQUAAAAAAAAAAAABABEhMRBBUWGRsfDx/9oACAEBAAE/EMXlTw6+IIl37QTtx1UsYKX3ABQBABor9TKjtnjT9dwMj0vjXH//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Firefox mouse click breakpoint" title="Firefox mouse click breakpoint" src="/static/a06ab13b3e8c1d082551f8bd5a632a91/b4294/firefox-mouseclickbreakpoint.jpg" srcset="/static/a06ab13b3e8c1d082551f8bd5a632a91/6f81f/firefox-mouseclickbreakpoint.jpg 270w, /static/a06ab13b3e8c1d082551f8bd5a632a91/09d21/firefox-mouseclickbreakpoint.jpg 540w, /static/a06ab13b3e8c1d082551f8bd5a632a91/b4294/firefox-mouseclickbreakpoint.jpg 600w" sizes="(max-width: 600px) 100vw, 600px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <p>Once enables, you could follow the same procedure we described before. First click on the calculate age button and the debugger automatically pauses on the first function call. In case of using a platform like Glitch or CodePen, that might not be what you’re after, so simply press the <strong>Resume</strong> <span class="image-inline"> <span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 40px; " > <a class="gatsby-resp-image-link" href="/static/501c68561b6f855c6cf1de6ce7ace252/92935/firefoxplaypause.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 105%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAVABQDASIAAhEBAxEB/8QAGAABAQADAAAAAAAAAAAAAAAAAAEDBAX/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAHtXFDZBKAH/8QAGhAAAgIDAAAAAAAAAAAAAAAAAQIAEgMRIP/aAAgBAQABBQJ2qFYMJlOgBd+P/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPwEf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPwEf/8QAHhAAAQIHAQAAAAAAAAAAAAAAAQACEBESICExUrH/2gAIAQEABj8C1NYg0npB4FI9t//EABwQAQACAgMBAAAAAAAAAAAAAAEQEQBBMWFx4f/aAAgBAQABPyGmbJaAyxP3qCQUAtxKQN7+YQeZ/9oADAMBAAIAAwAAABBjDzz/xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/EB//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/EB//xAAcEAEBAAEFAQAAAAAAAAAAAAABERAAIUFRcTH/2gAIAQEAAT8QlxW0Cr7rfkjAkV0nDgtDtGAb6aACWQ+k49b+YAgE+xLn/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Firefox resume button" title="Firefox resume button" src="/static/501c68561b6f855c6cf1de6ce7ace252/92935/firefoxplaypause.jpg" srcset="/static/501c68561b6f855c6cf1de6ce7ace252/92935/firefoxplaypause.jpg 40w" sizes="(max-width: 40px) 100vw, 40px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span> </span> button until you see the breakpoint stop at the <code class="language-text">getAge</code> function. Then click on the <strong>Step In</strong> <span class="image-inline"> <span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 24px; " > <a class="gatsby-resp-image-link" href="/static/b79eefda6281883132a3243493b5955e/0bf61/firefoxstepin.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 83.33333333333334%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAARABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAEEBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAe3Gc2AAoP/EABoQAAICAwAAAAAAAAAAAAAAAAECABEQEiD/2gAIAQEAAQUCJIiNth6pVKHj/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPwEf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPwEf/8QAHBAAAgICAwAAAAAAAAAAAAAAAREAIQIQIEGB/9oACAEBAAY/AqxcNJaRfgjzLvocf//EAB8QAQABAgcBAAAAAAAAAAAAAAERAEEQICExUXGBsf/aAAgBAQABPyGIk9hV2JQjguQ3Z+UlSGQPr3W5k//aAAwDAQACAAMAAAAQkwAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPxAf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPxAf/8QAHhABAAICAgMBAAAAAAAAAAAAAQARMUEhkRBRgbH/2gAIAQEAAT8Qz6M1U7ZStdAD+eDNDqgE3wa+xLxEW3sA9YggJsvniG5uGJ//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Firefox step in button" title="Firefox step in button" src="/static/b79eefda6281883132a3243493b5955e/0bf61/firefoxstepin.jpg" srcset="/static/b79eefda6281883132a3243493b5955e/0bf61/firefoxstepin.jpg 24w" sizes="(max-width: 24px) 100vw, 24px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span> </span> button or press <kbd>F11</kbd> to go inside the function. Once you’re inside the function simply press <strong>Step over</strong> <span class="image-inline"> <span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 18px; " > <a class="gatsby-resp-image-link" href="/static/28df88b8fcd63653687b9d1528a2c4a1/156d6/firefoxstepover.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 88.88888888888889%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAASABQDASIAAhEBAxEB/8QAGQABAAMBAQAAAAAAAAAAAAAAAAECAwQF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB9yKYnYoIzDoB/8QAHBAAAgICAwAAAAAAAAAAAAAAAQIAAxASETIz/9oACAEBAAEFAiQIGDY15st2iDVX6UeE/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPwEf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPwEf/8QAHBAAAgIDAQEAAAAAAAAAAAAAAAECIRARcUGB/9oACAEBAAY/Areinht/DcYX40JEuEOY/8QAHBABAAEEAwAAAAAAAAAAAAAAAQAQETFhIaHh/9oACAEBAAE/ITbkNzHTTiO4FpBcK+yacneVD//aAAwDAQACAAMAAAAQ4A88/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPxAf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPxAf/8QAHRABAAICAgMAAAAAAAAAAAAAAREhADFRgRBB8P/aAAgBAQABPxCxwRKjJsXLQbOsEdM4ImCBsOWOdY8BCVHYGK3qcvVUWvtyrn2ONUVWFvj/2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Firefox step over button" title="Firefox step over button" src="/static/28df88b8fcd63653687b9d1528a2c4a1/156d6/firefoxstepover.jpg" srcset="/static/28df88b8fcd63653687b9d1528a2c4a1/156d6/firefoxstepover.jpg 18w" sizes="(max-width: 18px) 100vw, 18px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span> </span> button or <kbd>F11</kbd> to go line by line from thereon.</p> <p><img src="/252ca5c56aa00b316ffccba44665a81b/firefoxclickbreakpoint.gif" alt="Firefox mouse click breakpoint"></p> <h2 id="line-breakpoint" style="position:relative;"><a href="#line-breakpoint" aria-label="line breakpoint permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Line breakpoint</h2> <p>Line breakpoints are mainly used when you’ve narrowed down where the bug might actually be. In our case when we stepped through the <code class="language-text">getAge</code> function, we saw that the age is calculated based on the year, then there is an if condition which will be responsible to reduce the age by one if the month is less than the current month minus the month of birth.</p> <p>So we roughly know that if the age is calculated right in some cases and wrong by one year in others, the if condition is where we should set our line breakpoint on.</p> <p>There are two ways to do this in DevTools, one is to follow the event listener breakpoint flow explained above. But if you know the filename beforehand, you can simply open the file in the editor pane and scroll through until you reach the line you want.</p> <p>Once you’re there, simply click the line number and it will put a <strong>Line Breakpoint</strong> <span class="image-inline"> <span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 34px; " > <a class="gatsby-resp-image-link" href="/static/18dd708cb3542c6fb2b4bd9d923f3f88/fec30/linebreakpoint.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 47.05882352941176%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAJABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAwABBf/EABUBAQEAAAAAAAAAAAAAAAAAAAQF/9oADAMBAAIQAxAAAAE0HKIO9LT3f//EABoQAAICAwAAAAAAAAAAAAAAAAACAQMQETL/2gAIAQEAAQUC3IpQzNXhef/EABYRAQEBAAAAAAAAAAAAAAAAAAABMf/aAAgBAwEBPwFMf//EABYRAQEBAAAAAAAAAAAAAAAAAAEAMf/aAAgBAgEBPwFJ2//EABkQAQEAAwEAAAAAAAAAAAAAAAEAEBESMf/aAAgBAQAGPwL1nax1kv/EABsQAAEEAwAAAAAAAAAAAAAAAAEAESFREKHx/9oACAEBAAE/IegicMTCJRCCbvOuv//aAAwDAQACAAMAAAAQmO//xAAXEQEBAQEAAAAAAAAAAAAAAAABABEx/9oACAEDAQE/EBR7DAX/xAAWEQEBAQAAAAAAAAAAAAAAAAABABH/2gAIAQIBAT8QFJ6kv//EAB4QAAIBAwUAAAAAAAAAAAAAAAABETFBURCRobHx/9oACAEBAAE/EPYiG2UjTrvmC4UJM6c6XRwvR//Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Line Breakpoint icon" title="Line Breakpoint icon" src="/static/18dd708cb3542c6fb2b4bd9d923f3f88/fec30/linebreakpoint.jpg" srcset="/static/18dd708cb3542c6fb2b4bd9d923f3f88/fec30/linebreakpoint.jpg 34w" sizes="(max-width: 34px) 100vw, 34px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span> </span> icon on that line so that you’d know where the breakpoint is set. You can remove the breakpoint by simply clicking on it again.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 478px; " > <a class="gatsby-resp-image-link" href="/static/f26cdc68eb50c273efdd2c7472a3219d/0c439/linebreakpointcode.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 48.888888888888886%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHuVtIpf//EABQQAQAAAAAAAAAAAAAAAAAAACD/2gAIAQEAAQUCX//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAACD/2gAIAQEABj8CX//EABoQAQABBQAAAAAAAAAAAAAAAAEhABEgUZH/2gAIAQEAAT8hlkO0X1j/AP/aAAwDAQACAAMAAAAQjw//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAaEAEBAAIDAAAAAAAAAAAAAAABEQAxECHR/9oACAEBAAE/ENCClgyPiYdmK3fP/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Line breakpoint" title="Line breakpoint" src="/static/f26cdc68eb50c273efdd2c7472a3219d/0c439/linebreakpointcode.jpg" srcset="/static/f26cdc68eb50c273efdd2c7472a3219d/6f81f/linebreakpointcode.jpg 270w, /static/f26cdc68eb50c273efdd2c7472a3219d/0c439/linebreakpointcode.jpg 478w" sizes="(max-width: 478px) 100vw, 478px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <p>Now if you click the calculate age button, the program stops on the if condition. This part is exactly the same in both Chrome and Firefox.</p> <h2 id="checking-variable-values" style="position:relative;"><a href="#checking-variable-values" aria-label="checking variable values permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Checking variable values</h2> <p>When you’re stopped at the if condition, if you want to see what is the value of a variable, simply have a look at the debugger pane’s <strong>Scope</strong> section in Chrome or <strong>Scopes</strong> section in Firefox.</p> <h3 id="chrome-2" style="position:relative;"><a href="#chrome-2" aria-label="chrome 2 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Chrome</h3> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 948px; " > <a class="gatsby-resp-image-link" href="/static/49ae1e69c058eab1ab6c6609c5be18be/64e16/chromescope.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 38.51851851851852%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAIABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAECBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAd2AsD//xAAWEAEBAQAAAAAAAAAAAAAAAAAAEUH/2gAIAQEAAQUCjX//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAUEAEAAAAAAAAAAAAAAAAAAAAQ/9oACAEBAAY/An//xAAZEAABBQAAAAAAAAAAAAAAAAARABAhQVH/2gAIAQEAAT8hLULS3//aAAwDAQACAAMAAAAQcA//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAaEAEAAgMBAAAAAAAAAAAAAAABABEhQWGB/9oACAEBAAE/ELXXyDMiqidqf//Z'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Scope section in Chrome&#39;s debug pane" title="Scope section in Chrome&#39;s debug pane" src="/static/49ae1e69c058eab1ab6c6609c5be18be/64e16/chromescope.jpg" srcset="/static/49ae1e69c058eab1ab6c6609c5be18be/6f81f/chromescope.jpg 270w, /static/49ae1e69c058eab1ab6c6609c5be18be/09d21/chromescope.jpg 540w, /static/49ae1e69c058eab1ab6c6609c5be18be/64e16/chromescope.jpg 948w" sizes="(max-width: 948px) 100vw, 948px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <h3 id="firefox-2" style="position:relative;"><a href="#firefox-2" aria-label="firefox 2 permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Firefox</h3> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 886px; " > <a class="gatsby-resp-image-link" href="/static/0a4db696d8d23420ec7288a50cc025a8/72f09/firefoxscopes.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 53.333333333333336%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAECBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAd0tEDD/xAAXEAADAQAAAAAAAAAAAAAAAAAAAREg/9oACAEBAAEFAoPP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAFxAAAwEAAAAAAAAAAAAAAAAAARAgMf/aAAgBAQAGPwJYY//EABoQAAICAwAAAAAAAAAAAAAAAAABEBExUXH/2gAIAQEAAT8hFq3wtxPAj//aAAwDAQACAAMAAAAQiO//xAAXEQEAAwAAAAAAAAAAAAAAAAAAARFR/9oACAEDAQE/EFTr/8QAFxEBAAMAAAAAAAAAAAAAAAAAAAERUf/aAAgBAgEBPxBUY//EAB0QAAICAQUAAAAAAAAAAAAAAAABETEQUWGRodH/2gAIAQEAAT8QTJynyiJZVthrdXuLyh//2Q=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Scopes section in Chrome&#39;s debug pane" title="Scopes section in Chrome&#39;s debug pane" src="/static/0a4db696d8d23420ec7288a50cc025a8/72f09/firefoxscopes.jpg" srcset="/static/0a4db696d8d23420ec7288a50cc025a8/6f81f/firefoxscopes.jpg 270w, /static/0a4db696d8d23420ec7288a50cc025a8/09d21/firefoxscopes.jpg 540w, /static/0a4db696d8d23420ec7288a50cc025a8/72f09/firefoxscopes.jpg 886w" sizes="(max-width: 886px) 100vw, 886px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <h2 id="spotting-the-bug" style="position:relative;"><a href="#spotting-the-bug" aria-label="spotting the bug permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Spotting the bug</h2> <p>Now let’s see where the bug is and how to fix it. If you have a look at the if condition more closely, you’ll see that there are two main parts in there. First one is <code class="language-text">m &lt; 0</code> to check whether the month is less than zero, and the second is <code class="language-text">m = 0 &amp;&amp; today.getDate() &lt; birthDate.getDate()</code> to check if the month is zero and today is less than birthday.</p> <p>Now we know that someone’s used an equal sign instead of equality operator which has caused this bug. So let’s replace the <code class="language-text">=</code> with <code class="language-text">===</code> and then press <kbd>Ctrl</kbd>+<kbd>S</kbd> to save the changes. You can leave the breakpoint or remove it test with some dates to see if the bug is fixed or not. But after some tests we know that the bug is fixed. It’s time for you to go and write a test for this function so you won’t face the same bug again 😁.</p> <h2 id="console-window" style="position:relative;"><a href="#console-window" aria-label="console window permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Console window</h2> <p>Don’t forget that you can evaluate your expressions in the console window of the browser. As in you could simply put your condition in the console and see whether it’s returning <code class="language-text">true</code> or <code class="language-text">false</code>.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 410px; " > <a class="gatsby-resp-image-link" href="/static/f797b0fd457c2e9bb9dbbedf0fcafcca/0d3fb/consoleexpressionevaluation.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 21.85185185185185%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAEABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAEF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB3gUH/8QAFBABAAAAAAAAAAAAAAAAAAAAEP/aAAgBAQABBQJ//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAFBABAAAAAAAAAAAAAAAAAAAAEP/aAAgBAQAGPwJ//8QAFhABAQEAAAAAAAAAAAAAAAAAAAER/9oACAEBAAE/IWI//9oADAMBAAIAAwAAABAAD//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABcQAQEBAQAAAAAAAAAAAAAAAAERAOH/2gAIAQEAAT8QCjonDCG//9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Evaluating expressions in console window" title="Evaluating expressions in console window" src="/static/f797b0fd457c2e9bb9dbbedf0fcafcca/0d3fb/consoleexpressionevaluation.jpg" srcset="/static/f797b0fd457c2e9bb9dbbedf0fcafcca/6f81f/consoleexpressionevaluation.jpg 270w, /static/f797b0fd457c2e9bb9dbbedf0fcafcca/0d3fb/consoleexpressionevaluation.jpg 410w" sizes="(max-width: 410px) 100vw, 410px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <h2 id="what-else" style="position:relative;"><a href="#what-else" aria-label="what else permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>What else?</h2> <p>There are heaps of other breakpoints you could use such as conditional breakpoints which are triggered only if a condition you provide is <code class="language-text">true</code>, breakpoints on caught and uncaught exceptions, and XHR breakpoints which are triggered when a URL matches a substring you’ve set. Let’s try a XHR breakpoint in , open up your DevTools, head over to debug pane and open the <strong>XHR Breakpoints</strong> section. Click in the box to add a line and enter <code class="language-text">raw</code> and press <kbd>Enter</kbd>. Now refresh the page and you’ll see the breakpoint hit when the request is made. You can now use the same technique we saw earlier to step in the code and set a like breakpoint to debug further.</p> <h2 id="small-catch" style="position:relative;"><a href="#small-catch" aria-label="small catch permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Small catch</h2> <p>One catch is that you need to make sure that the function you’re debugging is in the scope which is tricky if you’re using DevTools. In order to get it working you need to set a line breakpoint somewhere where the function is in scope, then trigger the breakpoint and call <code class="language-text">debug()</code> in the DevTools console while the code is still paused on the line breakpoint.</p> <div class="gatsby-code-button-container" data-toaster-id="84003865602971100000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`(function () { function hello() { console.log('hello'); } function world() { console.log(' world'); } hello(yo); // This works. world(); })(); debug(hello); // This doesn't work. hey() is out of scope.`, `84003865602971100000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">function</span> <span class="token function">hello</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'hello'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">world</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">' world'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">hello</span><span class="token punctuation">(</span>yo<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// This works.</span> <span class="token function">world</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">debug</span><span class="token punctuation">(</span>hello<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// This doesn't work. hey() is out of scope.</span></code></pre></div> <h2 id="summary" style="position:relative;"><a href="#summary" aria-label="summary permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Summary</h2> <p>We saw how powerful the DevTools are and how much they can help us to find and fix bugs in our code. So stop using <code class="language-text">console.log</code> and get to know your DevTools better. Happy coding from home ❤️.</p><![CDATA[What you need to know about Full screen API 💻]]>https://yashints.dev/blog/2020/03/10/fullscreen-apihttps://yashints.dev/blog/2020/03/10/fullscreen-apiTue, 10 Mar 2020 00:00:00 GMT<p> There are many situations where we’d like to see our web page in fullscreen mode. Be it games, online courses, video tutorials, or simply wanting more reading space while reading a book. What we usually do in these sort of scenarios is we manually set our browser’s tab/window in fullscreen mode (<kbd>F11</kbd>), but the result is not always what we expect, because some content is not designed to be viewed in fullscreen mode. Besides, what if we help our users to go fullscreen automatically instead, again it all comes to having a better user experience.</p> <!--more--> <h2 id="intro" style="position:relative;"><a href="#intro" aria-label="intro permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Intro</h2> <p><a href="https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API">Full Screen API</a> adds methods to the HTML <code class="language-text">Element</code> to enable us to programmatically turn any content on a page to enter in fullscreen mode via JavaScript. <code class="language-text">WebGL</code>, <code class="language-text">canvas</code>, and <code class="language-text">video</code> elements are the usual targets when it comes to going fullscreen. Online newspapers and magazines are other areas where this can be helpful.</p> <p>So let’s see this in action first and then go through some details:</p> <iframe height="265" style="width: 100%;" scrolling="no" title="Full Screen API Demo" src="https://codepen.io/yashints/embed/preview/mdJpqYx?height=265&theme-id=light&default-tab=js,result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/yashints/pen/mdJpqYx'>Full Screen API Demo</a> by Yaser Adel Mehraban (<a href='https://codepen.io/yashints'>@yashints</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> <p>All we’re doing here is to call a method which is added by the Full Screen API:</p> <div class="gatsby-code-button-container" data-toaster-id="40904841840399220000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`const vid = document.getElementById('shuttle'); function toggleFullScreen() { if (!document.fullscreenElement && vid.requestFullscreen) { vid.requestFullscreen(); } else { if (document.exitFullscreen) { document.exitFullscreen(); } } } document.addEventListener(&quot;keydown&quot;, function(e) { if (e.keyCode == 13) { toggleFullScreen(); } }, false);`, `40904841840399220000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">const</span> vid <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'shuttle'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">toggleFullScreen</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>document<span class="token punctuation">.</span>fullscreenElement <span class="token operator">&amp;&amp;</span> vid<span class="token punctuation">.</span>requestFullscreen<span class="token punctuation">)</span> <span class="token punctuation">{</span> vid<span class="token punctuation">.</span><span class="token function">requestFullscreen</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>document<span class="token punctuation">.</span>exitFullscreen<span class="token punctuation">)</span> <span class="token punctuation">{</span> document<span class="token punctuation">.</span><span class="token function">exitFullscreen</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"keydown"</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>e<span class="token punctuation">.</span>keyCode <span class="token operator">==</span> <span class="token number">13</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">toggleFullScreen</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div> <h2 id="exposed-properties" style="position:relative;"><a href="#exposed-properties" aria-label="exposed properties permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Exposed properties</h2> <p>There are two properties exposed on the <code class="language-text">document</code> object:</p> <p>💡 <strong><code class="language-text">DocumentOrShadowRoot.fullscreenElement</code></strong></p> <p>The <code class="language-text">fullscreenElement</code> property will give you the element that is displayed in fullscreen mode at the moment. It’s a way to check whether we’re in full screen mode or not.</p> <p>💡 <strong><code class="language-text">Document.fullscreenEnabled</code></strong></p> <p>The <code class="language-text">fullscreenEnabled</code> property tells you whether or not the document is currently in a state that would allow fullscreen mode to be requested.</p> <h2 id="exiting-fullscreen" style="position:relative;"><a href="#exiting-fullscreen" aria-label="exiting fullscreen permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Exiting fullscreen</h2> <p>You’ll want to be sure to let your users know that they can press the <kbd>Esc</kbd> key (or <kbd>F11</kbd>) to exit fullscreen mode.</p> <p>In addition, navigating to another page, changing tabs, or switching to another application (using, for example, <kbd>Alt</kbd>-<kbd>Tab</kbd>) while in fullscreen mode exits fullscreen mode as well.</p> <p>As you saw in the example above, exiting the fullscreen mode can be done using <code class="language-text">document.exitFullscreen</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="53499161906692686000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`if (document.exitFullscreen) { document.exitFullscreen(); }`, `53499161906692686000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">if</span> <span class="token punctuation">(</span>document<span class="token punctuation">.</span>exitFullscreen<span class="token punctuation">)</span> <span class="token punctuation">{</span> document<span class="token punctuation">.</span><span class="token function">exitFullscreen</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div> <h2 id="feature-detection" style="position:relative;"><a href="#feature-detection" aria-label="feature detection permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Feature detection</h2> <p>You can simply detect whether the feature is supported or not using either <code class="language-text">document.requestFullscreen</code> or <code class="language-text">Element.requestFullscreen</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="40194777116596355000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`if(element.requestFullscreen) { element.requestFullscreen(); }`, `40194777116596355000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">if</span><span class="token punctuation">(</span>element<span class="token punctuation">.</span>requestFullscreen<span class="token punctuation">)</span> <span class="token punctuation">{</span> element<span class="token punctuation">.</span><span class="token function">requestFullscreen</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div> <p>or:</p> <div class="gatsby-code-button-container" data-toaster-id="16815096889626102000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`if(document.requestFullscreen) { // enter fullscreen mode }`, `16815096889626102000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">if</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span>requestFullscreen<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// enter fullscreen mode</span> <span class="token punctuation">}</span></code></pre></div> <h2 id="finding-whether-or-not-youre-in-fullscreen-mode" style="position:relative;"><a href="#finding-whether-or-not-youre-in-fullscreen-mode" aria-label="finding whether or not youre in fullscreen mode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Finding whether or not you’re in fullscreen mode</h2> <p>As mentioned earlier, the <code class="language-text">document.fullscreenElement</code> is a good way to check whether the browser is in full screen mode or not. The value of this property will be <code class="language-text">null</code> if we’re not in fullscreen, and the current fullscreen element otherwise.</p> <div class="custom-block warning"><div class="custom-block-body"><p>⚠️ There is also a <code class="language-text">boolean</code> property called <code class="language-text">fullscreen</code> which is deprecated and should not be used. Although most of the browsers still support it.</p></div></div> <h2 id="presentation" style="position:relative;"><a href="#presentation" aria-label="presentation permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Presentation</h2> <p>When toggling fullscreen mode programmatically, you’re responsible for how the elements will look like and what appears on the screen. It’s obvious you will need to change the width and height of the element to <code class="language-text">%100</code>, and fortunately, there is a CSS pseudo-selector for you to use:</p> <div class="gatsby-code-button-container" data-toaster-id="74492252166284150000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`#shuttle:fullscreen { width: 100%; height: 100%; }`, `74492252166284150000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">#shuttle:fullscreen</span> <span class="token punctuation">{</span> <span class="token property">width</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div> <p>Also you might want to hide some other elements on the screen to reduce clutter:</p> <div class="gatsby-code-button-container" data-toaster-id="23204515642718925000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`:fullscreen .hide { display: none; }`, `23204515642718925000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="css"><pre class="language-css"><code class="language-css"><span class="token selector">:fullscreen .hide</span> <span class="token punctuation">{</span> <span class="token property">display</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div> <h2 id="browser-support" style="position:relative;"><a href="#browser-support" aria-label="browser support permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Browser support</h2> <p>The browser support is really good at this point, almost all major browsers fully support it. Only <strong>IE11</strong> and <strong>Safari</strong> have partial support. Opera mini and Android Browser do not support it at this point.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1080px; " > <span class="gatsby-resp-image-background-image" style="padding-bottom: 27.77777777777778%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAB2HAAAdhwGP5fFlAAABuElEQVQY0yWOS2sTYRhG59/4A8SFC6ErFUEQsXRRNwZBaZSCil2I0hqsl2XahVioxsumtkgJic1lJrFNbZqmSRMn00wmmUxDm8wkmpGMomjh9BMXBw4vz8PzSr3sLG0jQ7et4rQr9Jwazr5K15Dxyi9xD8TNKtBvFelaeRyBK9xubtMxCzjmFu16jn1jE7uxjWTpeUytiDoXoDRzn1zwIebnOLXkMpknE1RzMUwRtgqyyKUxd9NYRRmjnMHQsuypCnoxiZpP0FIrSAf1FOX8DFllmPXEEKvxk5TnR5HnLzMdPU85EqS39pH+1yqureF2KuJrje/t/wz+0dkVXqVlvkGaDV5g6MUx7sQucle5xC15mIXUKUKpE/jFyOtXx1FCZ2nkEuwEJ9mausnG46uoiefo1TCbO2G0L1FKpXf4I2eQ5pZ9jL2/zeiSj5GlK4x8uEYocpq3K+d4EHvGYmYMJepjY3qC9clx1p6Ok1jxkVb8xD7d4FEywIJyD2X1OlPxANKvboPDroFupVHNJJWmwl4zTK8l89cx+Nkx8Ow6g286A7eO1xeIjmfX8Do1fts6P+yqcIM/js4R/XOCPlqtEn0AAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Browser support for Full Screen API" title="Browser support for Full Screen API" src="/static/2f6bdf83bea61460d60ed9d65117439e/302a4/caniuse.png" srcset="/static/2f6bdf83bea61460d60ed9d65117439e/01bf6/caniuse.png 270w, /static/2f6bdf83bea61460d60ed9d65117439e/07484/caniuse.png 540w, /static/2f6bdf83bea61460d60ed9d65117439e/302a4/caniuse.png 1080w, /static/2f6bdf83bea61460d60ed9d65117439e/0d292/caniuse.png 1620w, /static/2f6bdf83bea61460d60ed9d65117439e/b3608/caniuse.png 2160w, /static/2f6bdf83bea61460d60ed9d65117439e/9a6b5/caniuse.png 2817w" sizes="(max-width: 1080px) 100vw, 1080px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </span></p> <p>Hope you’ve learned a new trick if you didn’t know about this API and happy fullscreening (just made up the word 😁).</p><![CDATA[Stop gobbling up that memory 🛑]]>https://yashints.dev/blog/2020/02/28/mem-leakhttps://yashints.dev/blog/2020/02/28/mem-leakFri, 28 Feb 2020 00:00:00 GMT<p> I’ve been writing web applications for more than a decade. From <em>classic ASP</em> to <em>PHP</em>, <em>ASP.Net web forms</em> and the list goes on and on. However, something that’s been common between all those years for me has been to care about how performing the site is. One important part of that has been to look out for memory leaks, because they can cause the page to go super slow or even crashing in more serious scenarios. </p> <!--more--> <h2 id="intro" style="position:relative;"><a href="#intro" aria-label="intro permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Intro</h2> <p>Memory leaks are a common problem in software development, regardless of whether the language you’re using is memory managed or not. By that I mean languages which come with a garbage collector. Memory leaks happen when a piece of memory is allocated, but never freed by the application, and is not returned to the container app or the operating system.</p> <p>I remember going through the concept in uni, but I can’t remember anything apart from the fact that usually there is a tree made up of all the occupied memory locations. Every time the garbage collector is looking into the memory parses that tree, and if a node is not connected to any branch, it gets recollected and returned to the main program.</p> <p>Most of us web developers are likely to use one of the major frameworks or libraries to write our applications. Some maybe using a bit older languages like PHP or Ruby, but no matter what we use, there will be a high chance that we come face to face with this problem one way or another.</p> <h2 id="consequences" style="position:relative;"><a href="#consequences" aria-label="consequences permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Consequences</h2> <p>So what happens when there is a memory leak in our applications 🤔?</p> <p>In some cases the memory consumption just keeps going up. If the user is using a decent spec machine, they might not even realise it. Not everyone is obsessed like us developers checking their task manager often to see how much memory is consumed.</p> <p>Regardless, it slows down the page, makes interactions not responsive, and might even cause the tab or the whole window to crash.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 454px; " > <a class="gatsby-resp-image-link" href="/static/cdb290cc2bda873f8fddf9f864018bbb/b3c1d/memoryleak.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 63.70370370370371%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAAAsSAAALEgHS3X78AAABRUlEQVQ4y61T226DMAzl//9jT/uHSZ3EJh4rFSpBUClSWqkk5R4KJfVsoNA+bdAhHdmOksPJsWMEQfAhpdxHUeRhZEsghPDiOA6Ra2Vgsod/+s7nMzdI2fF4BM/z2qqq9PV61U3TzEJd1y0RotKdgWTMdV3Ybreacw632w1wEyDxGH8DkQ6EASkkDyAMQ50kCbRt2xHdMZuQTB0s0CgOtNZPhH/Eo8ITo6vyA9fMZ+D7fqdyJiZCIQUrVUkd0kJKOEURKKWgLMsRClEURZ+rPr/XFPM8fyAUgl0uVUeYpilkWQYUkzQB8hTHCtIh4p5xDYXgvj7HPnSEaN/kIXZXU4cfr0J+0m2mfFq/10N8Uujh/NGfW1RHM7UE3Ryi0h29lJAK8qNp6pdeCnIdDMuy3hzH+bJte7XZbD7X6/US0Nlv0zTffwBfPN3s7UKdGgAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Memory leak in google chrome" title="Memory leak in google chrome" src="/static/cdb290cc2bda873f8fddf9f864018bbb/b3c1d/memoryleak.png" srcset="/static/cdb290cc2bda873f8fddf9f864018bbb/01bf6/memoryleak.png 270w, /static/cdb290cc2bda873f8fddf9f864018bbb/b3c1d/memoryleak.png 454w" sizes="(max-width: 454px) 100vw, 454px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <h2 id="memory-leak-in-javascript" style="position:relative;"><a href="#memory-leak-in-javascript" aria-label="memory leak in javascript permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Memory leak in JavaScript</h2> <p>It’s way easy in JavaScript to allocate some memory and forget about it. Even if you’re not writing plain JavaScript, it’s still possible that a memory leak happen, without you noticing it.</p> <h3 id="but-how-does-it-happen" style="position:relative;"><a href="#but-how-does-it-happen" aria-label="but how does it happen permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>But how does it happen?</h3> <p>In JavaScript there are a few possible ways a memory leak can happen.</p> <ul> <li>Unintentionally creating global variables</li> <li>Timers and callbacks</li> <li>Out of DOM references</li> <li>Closures</li> <li>Event listeners</li> </ul> <h3 id="global-variables" style="position:relative;"><a href="#global-variables" aria-label="global variables permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Global variables</h3> <p>It’s very simple to create an unwanted global variable in JavaScript. Consider below code:</p> <div class="gatsby-code-button-container" data-toaster-id="90067203671980380000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`function helloWorld() { name = 'Yas'; console.log(\`Hello \${name}\`); }`, `90067203671980380000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">helloWorld</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> name <span class="token operator">=</span> <span class="token string">'Yas'</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Hello </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div> <p>In this simple function we have created a global variable called name. We didn’t want to, but we did it anyway.</p> <blockquote> <p>💡 A reference to an undeclared variable creates a new variable inside the global object.</p> </blockquote> <p>Same thing can happen if you use <code class="language-text">this</code>:</p> <div class="gatsby-code-button-container" data-toaster-id="95079430483545150000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`function helloWorld(args) { this.name = 'Yas'; console.log(\`Hello \${name}\`); }`, `95079430483545150000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">helloWorld</span><span class="token punctuation">(</span><span class="token parameter">args</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">'Yas'</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Hello </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div> <div class="custom-block danger"><div class="custom-block-body"><p>To prevent these sorts of leaks, use JavaScript in <code class="language-text">strict</code> mode. You can do it by adding <code class="language-text">use strinct;</code> at the top of your JavaScript file.</p></div></div> <p>Even thought we consider accidental global variables one of the memory leak sources, there are still many global variables defined by the framework we use, or even the ones we intend to be there. Remember these are non collectable variables and unless nulled or reassigned, garbage collectors can’t do anything about them.</p> <h3 id="timers-and-callbacks" style="position:relative;"><a href="#timers-and-callbacks" aria-label="timers and callbacks permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Timers and callbacks</h3> <p>The use of <code class="language-text">setInternal</code> and <code class="language-text">setTimeout</code> has gotten less and less popular as we’ve moved towards more modern concepts like <code class="language-text">async/await</code>. Furthermore, some libraries and frameworks provide observables to facilitate callbacks. In which case they’re responsible for making sure the callbacks are unreachable once their own instance gets destroyed.</p> <p>However, there are quite a number of scenarios where we need to use it in order to call a function at a later time or on a schedule.</p> <div class="gatsby-code-button-container" data-toaster-id="72307958856726766000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`let data = fetchData(); setInternal(function() { let node = document.querySelector('#list'); // loop through data and create the html node.innerHTML = transform(data); }, 1000)`, `72307958856726766000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">let</span> data <span class="token operator">=</span> <span class="token function">fetchData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setInternal</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> node <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'#list'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// loop through data and create the html</span> node<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> <span class="token function">transform</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span></code></pre></div> <p>This example shows how a timer can turn into something that cannot be collected. Even if the list node is removed from the DOM, the reference inside the handler remains active and cannot be collected. That causes their dependencies to be non collectable as well. So the data variable which might be really large, would sit in memory long after its need has ended.</p> <p>Now let’s see how we can improve this to avoid a memory leak:</p> <div class="gatsby-code-button-container" data-toaster-id="23435050791474676000" data-toaster-class="gatsby-code-button-toaster" data-toaster-text-class="gatsby-code-button-toaster-text" data-toaster-text="Copied to clipboard ✅" data-toaster-duration="3500" onClick="copyToClipboard(`let node = document.querySelector('#list'); let data = fetchData(); function handler(data) { if(node) { // do stuff with data and create the list node.innerHTML = transform(data); } }; setInterval(handler, 1000);`, `23435050791474676000`)" > <div class="gatsby-code-button" data-tooltip="" > Copy<svg class="gatsby-code-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z"/></svg> </div> </div> <div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token keyword">let</span> node <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'#list'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">let</span> data <span class="token operator">=</span> <span class="token function">fetchData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">handler</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span><span class="token punctuation">(</span>node<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// do stuff with data and create the list</span> node<span class="token punctuation">.</span>innerHTML <span class="token operator">=</span> <span class="token function">transform</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token function">setInterval</span><span class="token punctuation">(</span>handler<span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div> <h3 id="out-of-dom-references-detached-dom" style="position:relative;"><a href="#out-of-dom-references-detached-dom" aria-label="out of dom references detached dom permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Out of DOM references (detached DOM)</h3> <p>When some nodes are removed from the DOM but still exists in memory through JavaScript, we have out of DOM references