<![CDATA[Untitled RSS Feed]]>http://github.com/dylang/node-rssGatsbyJSThu, 02 Dec 2021 09:52:49 GMT<![CDATA[My first ever book on Azure Bicep]]>https://yashints.dev/blog/2021/12/02/bicep-bookhttps://yashints.dev/blog/2021/12/02/bicep-bookThu, 02 Dec 2021 00:00:00 GMT<p>I’ve contributed to the development community in many ways, be it speaking at conferences, writing technical blog posts, getting involved in conferences as volunteer or part of the crew, or helping with Hackatons and Open Hacks. However, writing a book has been in my todo list for quite a while, and honestly, I’ve been afraid to start due to various reasons, mainly because I heard how much time and energy you need to put into it.</p> <p>Regardless, I set it as a goal in 2021 and after a few months working on it, voila, <a href="https://www.amazon.com/author/yas">it’s now listed on Amazon</a> to be published early next year. I am so excited about it and thought to share my experience and how I reached this milestone.</p> <!--more--> <h2 id="why-would-you-want-to-write-a-book" style="position:relative;"><a href="#why-would-you-want-to-write-a-book" aria-label="why would you want to write a book 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>Why would you want to write a book?</h2> <p>Writing a book might seem like a far fetched goal, in fact there are many smart and talented people out there writing great technical books on various topics which become best sellers. So you might be asking yourself why would I even think about it.</p> <p>However, before we go further let me tell you a few things:</p> <ul> <li>Anyone can learn to write a book, and I mean anyone!</li> <li>If you like writing technical content, be it blog posts or even documentation, you can pull this off easier than you think.</li> </ul> <p>So let’s go back to why you should write a book. I would share my own reasons, but you might find them relatable too.</p> <h3 id="sharing-your-knowledge-with-others" style="position:relative;"><a href="#sharing-your-knowledge-with-others" aria-label="sharing your knowledge with 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>Sharing your knowledge with others</h3> <p>You might be good in a subject and have worked with it for a long time. You might even not have worked with it but be very passionate about it and wanted to share what you learn with others to help them succeed. For this exact reason, I believe it’s important to think about writing a book if you have enough in your mind to make it work.</p> <p>I have read books before and they have helped me reach where I am because I’ve always progressed as a self-thought individual rather than being academic or even as a trainee. So it was important for me to give it back somehow and finally it happened, think about it.</p> <h3 id="it-would-add-to-your-credit-professionally" style="position:relative;"><a href="#it-would-add-to-your-credit-professionally" aria-label="it would add to your credit professionally 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>It would add to your credit professionally</h3> <p>From a professional perspective, writing a book will add to your creditability and establish you as an expert in that field. Who knows, it might also help you land a great job, think about your interviewer when you tell them you have a book on the subject and how positively it can affect the process.</p> <h3 id="ticking-a-box-accomplishing-a-new-goal" style="position:relative;"><a href="#ticking-a-box-accomplishing-a-new-goal" aria-label="ticking a box accomplishing a new goal 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>Ticking a box, accomplishing a new goal</h3> <p>If you have a todo list and have some goals for yourself, why not put writing a book in there too. Think about how accomplished you feel when you actually do it. You will tackle a new challenge and prove to yourself that nothing is impossible if you put your energy into it. </p> <h3 id="you-will-learn-a-lot" style="position:relative;"><a href="#you-will-learn-a-lot" aria-label="you will learn a lot 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>You will learn a lot</h3> <p>Writing a book can help you learn a lot in a specific subject. When you are writing a book, it becomes important that you validate your knowledge and back everything with facts and data. During this process you will learn new things in every step of the way and that to me is worth all the time and energy you put into it.</p> <h3 id="you-might-make-money" style="position:relative;"><a href="#you-might-make-money" aria-label="you might make money 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>You might make money</h3> <p>Not every goal is about money, but if you can make a few extra bucks publishing your book, why not. You have put your time on it and getting rewards in form of a currency (😎) can be very helpful to anybody.</p> <p>Now that I mentioned my reasons, think about what else and let me know, I am keen to hear yours too. Enough about reasons, let’s talk about the process.</p> <h2 id="the-uhowu" style="position:relative;"><a href="#the-uhowu" aria-label="the uhowu 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 <u>HOW</u></h2> <p>It is no secret that writing a book requires discipline and good time management. But let me tell you it needs a little bit more than that, in my case anyway. You might have to put extra effort or be a bit more proficient than me, so take this with a grain of salt.</p> <h3 id="finding-a-topic" style="position:relative;"><a href="#finding-a-topic" aria-label="finding a topic 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 topic</h3> <p>First thing you need to do is to find a topic, but you can’t find any topic. You need to find something that you’re good at it, and you really believe it’s important to share it with others. In my case <a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/overview">Azure Bicep</a> is a new tool, there are not many books written on it, and I am really passionate about how it can help people achieve more by doing less.</p> <blockquote> <p>If you want to publish your book, you also need to find a topic where there are not many books available by other writers on it.</p> </blockquote> <h3 id="form-an-outline" style="position:relative;"><a href="#form-an-outline" aria-label="form an outline 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>Form an outline</h3> <p>It’s important to have an outline to be able to tell a story. Yes, you heard me right, even a technical book needs a story if you want it to be effective. You need a <em>beginning</em>, <em>middle</em> and <em>end</em> which takes your readers on a journey. Start with simples, then move to advanced areas and then finish off by some best practices or something that compliments your points and helps them a few extra steps.</p> <h3 id="read-it-yourself" style="position:relative;"><a href="#read-it-yourself" aria-label="read it yourself 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>Read it yourself</h3> <p>I can’t emphasis enough how important it is to read what you write first. If you feel you’re biased, get somebody else to read it and give you feedback. Sometimes we don’t realise how we fall into trap of making assumptions and the book turns out to be useless because of that.</p> <h3 id="set-a-schedule" style="position:relative;"><a href="#set-a-schedule" aria-label="set a schedule 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>Set a schedule</h3> <p>If you are a full time employee like me, you need to set a schedule for yourself and make it a habit. Lock it in your calendar and make sure it’s a time with minimal disruptions. I used one hour every night from 10pm to 11pm when my kids were in bed and I had already finished my dad duties. But I kept it like that for 4 months until I finished the book and boy that helps.</p> <p>If that doesn’t work for you, you can set a goal for how many words need to write each day, week, months, etc.</p> <h3 id="use-writing-tools" style="position:relative;"><a href="#use-writing-tools" aria-label="use writing tools 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 writing tools</h3> <p>Books are different that blog posts in a sense that they need to be credible. Having grammar errors or spelling mistakes will look really bad, so use a software which helps you proofread your writing.</p> <p>And that’s all I did to be able to be here writing this post.</p> <h2 id="finishing-touches" style="position:relative;"><a href="#finishing-touches" aria-label="finishing touches 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>Finishing touches</h2> <p>It can become a really hard job even from start, so keep yourself motivated. If you face any setbacks or challenges, try to positively face them and work your way around solving those slowly and steadily.</p> <p>Reward yourself, give yourself a little treat at the end of every chapter, or section. This definitely helped me, so it will probably help you too.</p> <p>I hope this has motivated you to at list think about the possibility of wiring a book. Anyway, I didn’t talk about the book itself, so read on.</p> <h2 id="about-my-book" style="position:relative;"><a href="#about-my-book" aria-label="about my book 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>About my book</h2> <p><a href="https://www.amazon.com/gp/product/B09MFY582M/ref=dbs_a_def_rwt_bibl_vppi_i0">Infrastructure as code with Azure Bicep</a> is a book which takes you on a journey from what Azure Bicep is, to how it works and its syntax. Then you learn about all the bits and pieces to be able to write maintainable, reusable, modular templates to be able to deploy your resources into your Azure environment with confidence. It also covers the authoring experience and how amazing it is to work with it from Visual Studio Code and its extension. </p> <p>Then it covers how to use it in your CI/CD pipelines both on Azure DevOps and GitHub actions. And at last we will cover some advanced topics to add that extra bit of tidbits which makes you stand out when writing infrastructure as code such as some best practices and patterns when deploying multiple environments.</p> <p>So keep an eye out and support me and my book if you can 😍🙏🏽.</p><![CDATA[Crowbits - STEM toy for kids 😍]]>https://yashints.dev/blog/2021/07/19/crowbitshttps://yashints.dev/blog/2021/07/19/crowbitsMon, 19 Jul 2021 00:00:00 GMT<p>Last year I backed up the <a href="https://www.kickstarter.com/projects/elecrow/crowbits-electronic-blocks-for-stem-education-at-any-level">Crowbits</a> project on Kickstarter because I saw a potential for kids to learn so much by assembling these kits especially that it could be integrated with lego’s.</p> <p>At the moment you can purchase the kits from the <a href="https://www.elecrow.com/crowbits-kit/kits.html">Elecrow</a>’s website. And just worth mentioning that this post is not sponsored, nor do I have any association with the team or any money from sharing these links is in play.</p> <!--more--> <h2 id="what-are-they" style="position:relative;"><a href="#what-are-they" aria-label="what are they 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 are they?</h2> <p>To me Crowbits are the coolest coding toys that I’ve seen so far. With more than 80+ electronic blocks, and a kid friendly graphical software, it really stands up from other similar products and creates a whole other level of fun for kids (and adults, I had fun too 😁).</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1000px; " > <a class="gatsby-resp-image-link" href="/static/c2058eaa57fae3fdcffd5e6541fdd8a6/a2510/crowbits1.jpg" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 100%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGQABAQEAAwAAAAAAAAAAAAAAAAIDAQQF/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAH1qiGe6k1nyJqF/8QAGRAAAgMBAAAAAAAAAAAAAAAAAQIQERID/9oACAEBAAEFAmYg6MNQJpYbmrHKx//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQMBAT8BH//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BH//EABoQAAIDAQEAAAAAAAAAAAAAAAABEBExISL/2gAIAQEABj8CF5uOit7FsyP/xAAbEAACAgMBAAAAAAAAAAAAAAABEQAxECFBcf/aAAgBAQABPyFLAcIyiDaNYIlt3FmqccDiAF+ypgVrH//aAAwDAQACAAMAAAAQyMdA/8QAFxEBAQEBAAAAAAAAAAAAAAAAARAhMf/aAAgBAwEBPxAd7AJ//8QAFhEAAwAAAAAAAAAAAAAAAAAAASAx/9oACAECAQE/EDE//8QAHRABAAMBAAIDAAAAAAAAAAAAAQARITEQUWFxgf/aAAgBAQABPxC+M/Dxly2RBf4e+B4kKL6XEihWjLc+iAXXuPVlmIi2kAF1o5Cf/9k='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Crowbits kit" title="Crowbits kit" src="/static/c2058eaa57fae3fdcffd5e6541fdd8a6/a2510/crowbits1.jpg" srcset="/static/c2058eaa57fae3fdcffd5e6541fdd8a6/6f81f/crowbits1.jpg 270w, /static/c2058eaa57fae3fdcffd5e6541fdd8a6/09d21/crowbits1.jpg 540w, /static/c2058eaa57fae3fdcffd5e6541fdd8a6/a2510/crowbits1.jpg 1000w" sizes="(max-width: 1000px) 100vw, 1000px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;" loading="lazy" /> </a> </span></p> <h2 id="modes" style="position:relative;"><a href="#modes" aria-label="modes 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>Modes</h2> <p>There are two modes you could play with this set, no-code and code modes. In this mode you just stick the pieces together and make a project using cardboard, lego pieces, strings and other crafting tools.</p> <p><img src="/a0aa0c20efeed02ff93eb41191118b5a/robot.gif" alt="Crowbits robot walking"></p> <p>In the coding mode, they use a software which helps them understand how the order of pieces should be and what happens when they connect them together. They don’t need to write any code, rather drag and drop the blocks in the software to make something like a robot, or tell the robot what to do next.</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/3b500477371f4b8c8871580b90c2ab12/29114/code.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,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB6klEQVQoz5WRzU8TYRDG92/ypARKQFIPmHjBk3cPevZkIamA0HKRDz3oxoaPZqFZ6NJF27oFBWPTbD+yVAnakq4tLbXQbdnd7gdv2R0WpBU1Hnwyh5nM83sn7wwGV+T1+QdHnw27nz9xTY24J4dd087xqRHXzNjEC6dzbJ2JWB7TNNt+7Ly+yDRNeUVu4aHcPJMjtspktOLbzHs3CpNhfiJSnlmLB4M0/C6snVkwm9yN5qBpFT8CUPTBxaAEAvoEaNX4sLMHxqnZGnYJixp6l5GCqYPwx+R8TNebEGdTycQny6SpOnvI+YvMUm45nAj/4tpwvNTop4t38V2CjnpjTb6mpt/LLCMbgHQdlaRoXlpJVxY2k2uWuYHMmgrIaMGJgnI7JA14SqsMR6XhuwjaNnWcCliGU4RKNajLIMpNlvuaqRrrPGzwcKi0YI7X7nmU++Pl6YX4UkzMF4+Ohf2asC/URUGoZwvVTKG6na0sRj4v7oCHA+ILSCdt+Jv68OmRwyHdGXjQ1dtzy27vs/d3dt+80Wnr6OrusPXYeu3XrtuGRt2aYS3IbKDLv5/DfL7x2LE39CjrX3lDrZLkMklRgdm5WRx/aYXnNU4QXitCbwOyJF49NfbzHqqqKYoKpgn/I+xfDfMvAfz59BlINTBdHL5z9wAAAABJRU5ErkJggg=='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Crowbits letscode software" title="Crowbits letscode software" src="/static/3b500477371f4b8c8871580b90c2ab12/302a4/code.png" srcset="/static/3b500477371f4b8c8871580b90c2ab12/01bf6/code.png 270w, /static/3b500477371f4b8c8871580b90c2ab12/07484/code.png 540w, /static/3b500477371f4b8c8871580b90c2ab12/302a4/code.png 1080w, /static/3b500477371f4b8c8871580b90c2ab12/0d292/code.png 1620w, /static/3b500477371f4b8c8871580b90c2ab12/29114/code.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></p> <h2 id="kits" style="position:relative;"><a href="#kits" aria-label="kits 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>Kits</h2> <p>There are different types of kits you can purchase:</p> <ul> <li><strong>Hello kit</strong>: With this kit you will get a flashing window light, pandora’s box, cute little dog and morse code machine.</li> <li><strong>Explorer kit</strong>: With this kit you will jump a notch to minsweeper, climbing monkey, piggy bank, the smart fan, ski and quadruped robots, and much more.</li> <li><strong>Inventor kit</strong>: This kit gets you the gesture control and bluetooth cars, obstacle avoidance car, elevator, automatic door, and a whole bunch of cool other projects.</li> <li><strong>Creator kit</strong>: You can build a horse racing project, catch the fruit game, crazy bird, tank wars and much more with this one.</li> <li><strong>Master kit</strong>: This one gets you phone, game console, radar and more advanced projects.</li> </ul> <h2 id="so" style="position:relative;"><a href="#so" aria-label="so 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>So</h2> <p>So don’t wait, go order your desired kit and get your kids (or yourself) busy building cool stuff.</p><![CDATA[Azure Active Directory - Concepts simplified 🔑]]>https://yashints.dev/blog/2021/07/02/azure-ad-conceptshttps://yashints.dev/blog/2021/07/02/azure-ad-conceptsFri, 02 Jul 2021 00:00:00 GMT<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/app-objects-and-service-principals#application-registration">Application registration, service principal</a>, <a href="https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview">system-assigned managed identity, user-assigned managed identity</a>, Enterprise Application, these are just a few concepts in Microsoft Identity Platform which helps businesses protect their applications and provide authentication and authorization using Azure Active Directory (aka AAD).</p> <p>There are many scenarios which can be covered using these concepts and although Microsoft has a ton of documentation around these, people get confused simply because of sheer amount of information to digest. So the point of these series is to get people to understand these concepts and apply them in their products developed on top of Azure AD without having to get information overload. In this post we will cover the basics.</p> <!--more--> <h2 id="pre-requisites" style="position:relative;"><a href="#pre-requisites" aria-label="pre requisites 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>Pre-requisites</h2> <p>Before we start going through these concepts, it’s worth mentioning we’re assuming our readers already know about a few concepts such as:</p> <ul> <li><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/overview-authentication">Authentication</a></li> <li><a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/authentication-vs-authorization">Authorization</a></li> <li><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/concept-mfa-howitworks">Multi-Factor authentication</a></li> <li><a href="https://docs.microsoft.com/en-us/azure/active-directory/manage-apps/what-is-single-sign-on">Single sign-on</a></li> </ul> <p>Before we go into Azure AD topics, we need to be on the same page with a few standards which are widely used in our industry.</p> <h2 id="openid-connect" style="position:relative;"><a href="#openid-connect" aria-label="openid connect 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>OpenID Connect</h2> <p><a href="https://openid.net/connect/">OpenID Connect (aka OIDC)</a> is an authentication protocol which makes things simple when it comes to authenticating a user or device. It leverages a trusted identity provider for authentication, and deals with applications in which users will sign into. For more information please refer to <a href="https://docs.microsoft.com/en-us/azure/active-directory/fundamentals/auth-oidc">our documentation here</a>.</p> <h2 id="oauth-20" style="position:relative;"><a href="#oauth-20" aria-label="oauth 20 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>OAuth 2.0</h2> <p>While OIDC deals with authentication, it relies on <a href="https://oauth.net/2/">OAuth 2.0</a> for authorization which allows a user to grant limited access to an application to its protected resources. This protocol is designed to work with HTTP protocol and separates the role of client from the resource owner. Again for more information please refer to <a href="https://docs.microsoft.com/en-us/azure/active-directory/fundamentals/auth-oauth2">our documentation</a>.</p> <p>Now that we know enough about these concepts, let’s dip our toes into the ocean.</p> <h2 id="service-principal" style="position:relative;"><a href="#service-principal" aria-label="service principal 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>Service Principal</h2> <p>Microsoft identity platform allows accessing resources to entities by a security principal which in case of a user is called <em>User Principal</em> and in terms of an application is called <em>Security Principal</em>. This object defines the access policy and permissions for the application in your tenant. This object is responsible for enabling core features such as authentication and authorization. There are different types of service principal, application, managed identity and legacy.</p> <h2 id="application-registration" style="position:relative;"><a href="#application-registration" aria-label="application registration 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>Application Registration</h2> <p>First off, we need to emphasize something, don’t get this confused with a web or console application. Since OAuth 2.0 and OpenID Connect work allow your applications to deal with users, Microsoft Identity Platform is restricting the identity and access management only for registered applications. This is where application registration comes into place, think of it as an entity representing your own application. This entity is registered in your tenant (Azure Active Directory instance dedicated to your organization) and you have full control over it.</p> <p>Through this app registration you get to specify which type of application will be using this to perform authentication, what type of scenarios are going to be covered (Client Credentials flow, Authorization Code flow, etc), whether it’s a single tenant app or a multi tenant one, etc. All of these are called identity configuration.</p> <p>Your app registration has two entities associated to it behind the scenes, <em>Application Object</em> and a <em>Service Principal Object</em>.</p> <h3 id="application-object" style="position:relative;"><a href="#application-object" aria-label="application object 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>Application Object</h3> <p>This object hold all the configuration of your application such as its name, and it’s properties such as a callback URL, logout URL, etc.</p> <h2 id="managed-identity" style="position:relative;"><a href="#managed-identity" aria-label="managed identity 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>Managed Identity</h2> <p>Managed identities are created to allow organizations and specifically developers to enable authentication and authorization without the need to have any credentials in place. This will simplify and secure the application implementation and mitigates many security risks which is caused by credentials leaked either by being committed to source code or being shared with many people. Just bare in mind that managed identities are designed to grant access to Azure Resources, meaning you can’t use a managed identity to secure an application hosted outside Azure.</p> <p>There are two types of managed identities, system assigned and user assigned. System assigned are created and destroyed with the service they belong to, whereas user assigned are independent services which have their own lifecycle and can be assigned to multiple cloud resources. You can see all of these in the below picture:</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/f1a459b5982d9051293a1efcebab7814/eb645/AADIdentities.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 66.66666666666666%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAABJ0AAASdAHeZh94AAACJ0lEQVQ4y41TTW/TQBT0P+bKpReQOFYIgegBBBck6JELDSB6IKWKUhJKqJvEqZLGTh1/xbH3w/FHPDzbTUhKi1gfdvet3+y8ebNKnucoxpLmuWnBVQeY6gayZVbGi/Pyn2K+3v9rKKuEJW30Lw1cPniJybc2ElSJq/T/BVVWi3SxgO+6sH9pmE1MOI5NtJfIo6g8wwbQmvVtgGma4sr30TEMmIyVQYszPPvZwateHzXPQ91xkCVJJU1xyQbgTWDlRNfx8EzFznkXb8ZjxFIiCEJ8mFp4MtaxR3p+J+ahPyNZ/iTfxVaZ2DZaxKBpWTAoKY4jAvSRxhJccsRUbsQ5PNfD5VCHPXUQsuBOUAX5shKbEiXjMA0bwx6VP5zDHLnIsgyM4t2TMRofVfz4qsH3Aro43gJbA64WQcBx0XKhNRz0GzZGbR+BK8B4iDiJMVRNnNYHaB6e40I1YDkWWWtThAp8DShFBNdg8C0B1/LBmYRPpUfEPGQhhBQIw7BsSkINklzAsxwUfiuq+IthMctIEIBE6crrOA8YIibWLEoJqGn1YRvvOp/QMrtUXbCh4S2tT+IEhm2i1j/GfvMAB2qdSrRLlxc2E0Lgxel73Kvt4tHRa+j+tDwrbK/c7FSxy5IUZ5MBHjfeYudwD/c/P0Xb6CJPqufIya8dU8Pzo310JhpYyEoptl7Klg3oE6SRXEQErKFnjzAL51hE1YuR5NUFaV5Yqpw3Ov4bypzhDRxmZDsAAAAASUVORK5CYII='); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Azure Active Directory Security Principal types" title="Azure Active Directory Security Principal types" src="/static/f1a459b5982d9051293a1efcebab7814/302a4/AADIdentities.png" srcset="/static/f1a459b5982d9051293a1efcebab7814/01bf6/AADIdentities.png 270w, /static/f1a459b5982d9051293a1efcebab7814/07484/AADIdentities.png 540w, /static/f1a459b5982d9051293a1efcebab7814/302a4/AADIdentities.png 1080w, /static/f1a459b5982d9051293a1efcebab7814/0d292/AADIdentities.png 1620w, /static/f1a459b5982d9051293a1efcebab7814/b3608/AADIdentities.png 2160w, /static/f1a459b5982d9051293a1efcebab7814/eb645/AADIdentities.png 2500w" 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="enterprise-application" style="position:relative;"><a href="#enterprise-application" aria-label="enterprise 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>Enterprise Application</h2> <p>And at last we have to talk about Enterprise Applications, these applications are generally representing applications that are created by other organizations and are accessible for you to subscribe to or use. Some are free to use whereas some you have to pay for. Something worth mentioning is that you would have an enterprise application even for your own apps. You can view a list of these applications from the <a href="https://docs.microsoft.com/en-us/azure/active-directory/saas-apps/">Azure App Gallery</a>. Once you have added the application to your tenant it will appear in your enterprise application menu in your Azure AD blade.</p> <p><span class="gatsby-resp-image-wrapper" style="position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; " > <a class="gatsby-resp-image-link" href="/static/d34bdb1d13f055f3a40484db210fe3ba/5a190/enterprise-applications-in-nav.png" style="display: block" target="_blank" rel="noopener" > <span class="gatsby-resp-image-background-image" style="padding-bottom: 60.370370370370374%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABJ0AAASdAHeZh94AAACKElEQVQoz3VS0W7TMBTNP08IbS3dirSnIVaGEOINCfgEXja6h4I0nnhCTAi1U6EtbZo4ie3YsePkcO2x0k4iytG917GPz7k30as37/Htxy9cE76PZzgZvMbD7lMc9AboHp2h2z8LsUPoPX6O3uEAHfq+/2iAve4AB/0X2D98hr3OKR50TxH1hgz9DzGOhgnefslwMalwcWNxPrEYTmtc/nS4nDrKHUazBu++ahyPChx/5OiPOI4/SZxcSTz5XOLl1RrR9bLEdL7CIk6RZBxSG2jjoEy9gd7KZVVDeGjKtY8WiTCIeRXORgtWEhlDTGQZl6jrGqaqYCxFY0JtKRpr4XxufV0BaP+hbelt0TiHKGWkLEmglIIUHOtcIxUWjGskhUJa6C0oJNwgKx0pbUlpSxEhVxZguUBUCIGyLFGRKq01VnGCeJ2goYs9nGvQULKpm1t4bUJIOlOhpgXnWmRZjmgtFGqy4x9PmhecNgpS7C/RwYa1JjjQWoU2tE0T9vt1v8dH35osy0ih5EjJsiSSmj6ssgKzxQLz+QJrWvcEy+WS6jniOEZRFKTGYfvx/UNQTJZn4xv8nowJE+REpKQE5xymbjYH/EYTBrFL0P4dxl1tyWm0WiZgpEDTzYbIvAKvpCLLTFTIVB2U+/42ZHWb4D6htx0JpalvOTX21oY/yBijQcnw/1nX7ijbJrivOBAmNBmWpmHSvvF5ngeLvtZUt22zQ/Q/3Fn+AzXGhG+xUVMtAAAAAElFTkSuQmCC'); background-size: cover; display: block;" ></span> <img class="gatsby-resp-image-image" alt="Enterprise Applications in Azure Active Directory" title="Enterprise Applications in Azure Active Directory" src="/static/d34bdb1d13f055f3a40484db210fe3ba/5a190/enterprise-applications-in-nav.png" srcset="/static/d34bdb1d13f055f3a40484db210fe3ba/01bf6/enterprise-applications-in-nav.png 270w, /static/d34bdb1d13f055f3a40484db210fe3ba/07484/enterprise-applications-in-nav.png 540w, /static/d34bdb1d13f055f3a40484db210fe3ba/5a190/enterprise-applications-in-nav.png 800w" sizes="(max-width: 800px) 100vw, 800px" 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>There are multiple different concepts when it comes to Azure Active Directory and using it for authentication and authorization of your applications. In this post we reviewed a few of the terms which are used in many different scenarios and saw what they are and when the come into picture. Hopefully now you have the background to delve into our next series of posts which cover scenarios and how to implement them using these entities.</p> <h2 id="up-next" style="position:relative;"><a href="#up-next" aria-label="up next 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>Up next</h2> <p>There are many different scenarios which can be addressed using Azure AD. Here are a few:</p> <ul> <li>A single page application (aka SPA) consuming a REST API both hosted on <a href="https://azure.microsoft.com/en-au/services/app-service/">Azure App Services</a> (using two separate app registration)</li> <li>A SPA consuming an <a href="https://azure.microsoft.com/en-au/services/functions/">Azure Function</a> (using app registration and managed identity)</li> <li>A SPA consuming an API hosted on <a href="https://azure.microsoft.com/en-au/services/api-management/">Azure API Management</a></li> <li>A multi-tenant API with a allowed list of tenants (using app registration and managed identity)</li> <li>Device code flow for input constraint devices such as Smart TV</li> <li>Using managed identity to access protected resources with EasyAuth</li> </ul> <p>In the upcoming series we will tackle each of these in turn, so stay tuned.</p><![CDATA[From ARM to Bicep 💪🏽]]>https://yashints.dev/blog/2021/05/10/from-arm-to-bicephttps://yashints.dev/blog/2021/05/10/from-arm-to-bicepMon, 10 May 2021 00:00:00 GMT<p>If you have deployed a resource in <a href="https://azure.microsoft.com/">Microsoft Azure</a> as part of your CI/CD pipeline you have probably worked with <a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/overview">ARM templates</a>. These templates can be used to automate your resource deployment to Azure and help you to have consistent environments whether it’s for testing, development or production purposes. However, there are some shortcomings when it comes to complex environments especially when you have many resources and the dependency between them makes the templates to be either super busy, very complex, or unreadable.</p> <p>For that Microsoft has introduced <a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/bicep-overview">Bicep</a> which is designed to overcome these issues and help you with your infrastructure as code setup.</p> <!--more--> <h2 id="whats-not-working-with-arm-templates" style="position:relative;"><a href="#whats-not-working-with-arm-templates" aria-label="whats not working with arm templates 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 not working with ARM templates?</h2> <p>Although there are some great features which make working with ARM templates a good experience such as functions, variables, nested templates etc, there is some room for improvements regarding below which has been raised by the community:</p> <ul> <li><strong>No comments</strong>: As of now you can’t use comments in the JSON files used by <a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/overview">Azure Resource Manager</a>. Since the users of ARM templates are mainly developers, comments would potentially help the next user to better understand the template and what’s going on in it. I’d personally argue with the fact that if you need comments in a template it probably means you need to refactor it, however, this is something which could come handy at times.</li> <li><strong>Parameter duplication</strong>: Since ARM templates are reusable, you would normally use parameters for customising the resource naming, number of resources to be deployed, pricing tier and so on. The problem is that these parameters would be needed and if you haven’t provided a default value you would get an error. So you might end up with lots of parameters repeated in different files for different environments, or simply replicating a single file and have lot’s of extra parameters which are not needed.</li> <li><strong>Validation</strong>: Although there is a validate command you can use to validate your templates, there might be times where validation doesn’t show you enough information or is not enough to prevent a failure in the actual run.</li> </ul> <h2 id="what-is-bicep" style="position:relative;"><a href="#what-is-bicep" aria-label="what is bicep 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 Bicep?</h2> <p>Bicep is a DSL (domain specific language) which can be used to write your Infrastructure as Code (IaC). Instead of writing ARM templates you write your code with Bicep and it will transpile it to ARM for you. It simplifies the authoring experience and addresses some of the issues we mentioned earlier. Compared to using JSON, Bicep can help you simplify the template definition a great deal. </p> <p>Let’s see this using a simple example. Imagine you are trying to create a storage account in Azure, with ARM template this is the minimum you will need:</p> <div class="gatsby-code-button-container" data-toaster-id="36959657669162760000" 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;\$schema&quot;: &quot;https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#&quot;, &quot;contentVersion&quot;: &quot;1.0.0.0&quot;, &quot;parameters&quot;: { &quot;storageAccountType&quot;: { &quot;type&quot;: &quot;secureString&quot; } }, &quot;variables&quot;: { &quot;diagStorageAccountName&quot;: &quot;[concat('diags', uniqueString(resourceGroup().id))]&quot; }, &quot;resources&quot;: [ { &quot;type&quot;: &quot;Microsoft.Storage/storageAccounts&quot;, &quot;apiVersion&quot;: &quot;2019-06-01&quot;, &quot;name&quot;: &quot;[variables('diagStorageAccountName')]&quot;, &quot;location&quot;: &quot;[resourceGroup().location]&quot;, &quot;sku&quot;: { &quot;name&quot;: &quot;[parameters('storageAccountType')]&quot; }, &quot;kind&quot;: &quot;Storage&quot; } ] }`, `36959657669162760000`)" > <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 property">"$schema"</span><span class="token operator">:</span> <span class="token string">"https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#"</span><span class="token punctuation">,</span> <span class="token property">"contentVersion"</span><span class="token operator">:</span> <span class="token string">"1.0.0.0"</span><span class="token punctuation">,</span> <span class="token property">"parameters"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"storageAccountType"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"secureString"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"variables"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"diagStorageAccountName"</span><span class="token operator">:</span> <span class="token string">"[concat('diags', uniqueString(resourceGroup().id))]"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"resources"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"Microsoft.Storage/storageAccounts"</span><span class="token punctuation">,</span> <span class="token property">"apiVersion"</span><span class="token operator">:</span> <span class="token string">"2019-06-01"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"[variables('diagStorageAccountName')]"</span><span class="token punctuation">,</span> <span class="token property">"location"</span><span class="token operator">:</span> <span class="token string">"[resourceGroup().location]"</span><span class="token punctuation">,</span> <span class="token property">"sku"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"[parameters('storageAccountType')]"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"kind"</span><span class="token operator">:</span> <span class="token string">"Storage"</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span></code></pre></div> <p>Using Bicep it will be simplified to:</p> <div class="gatsby-code-button-container" data-toaster-id="9516615791630590000" 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(`@secure() param storageAccountType string param location string = resourceGroup().location var diagStorageAccountName = concat('diags', uniqueString(resourceGroup().id)) resource diagsAccount 'Microsoft.Storage/storageAccounts@2019-06-01' = { name: diagStorageAccountName location: location sku: { name: storageAccountType } kind: 'Storage' }`, `9516615791630590000`)" > <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 function">secure</span><span class="token punctuation">(</span><span class="token punctuation">)</span> param storageAccountType string param location string <span class="token operator">=</span> <span class="token function">resourceGroup</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>location <span class="token keyword">var</span> diagStorageAccountName <span class="token operator">=</span> <span class="token function">concat</span><span class="token punctuation">(</span><span class="token string">'diags'</span><span class="token punctuation">,</span> <span class="token function">uniqueString</span><span class="token punctuation">(</span><span class="token function">resourceGroup</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">)</span> resource diagsAccount <span class="token string">'Microsoft.Storage/storageAccounts@2019-06-01'</span> <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> diagStorageAccountName location<span class="token operator">:</span> location sku<span class="token operator">:</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> storageAccountType <span class="token punctuation">}</span> kind<span class="token operator">:</span> <span class="token string">'Storage'</span> <span class="token punctuation">}</span></code></pre></div> <p>You can see how much time and space you could be saving if you were to use Bicep.</p> <h2 id="benefits" style="position:relative;"><a href="#benefits" aria-label="benefits 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>Benefits</h2> <p>When it comes to the benefits of using Bicep, there is a list published in our documentation:</p> <ul> <li>Support for all resource types and API versions.</li> <li>Better authoring experience using editors such as VS Code (you will get validation, type-safety, intellisense).</li> <li>Modularity can be achieved using <a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/bicep-modules">modules</a>. You can have modules representing an entire environment or a set of shared resources and use them anywhere in a Bicep file.</li> <li>Integration with Azure services such as Azure Policy, Templates specs, and Blueprints.</li> <li>No need to store a state file or keep any state. You can even use the <a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/template-deploy-what-if">what-if operation</a> to preview your changes before deploying them.</li> <li>Bicep is open source with a strong community supporting it.</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> <p>Every Bicep resource will have the below syntax:</p> <div class="gatsby-code-button-container" data-toaster-id="65275529914850394000" 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(`resource <symbolic-name> '<resource-type>@<api-version>\` = { //properties name: 'bicepstorage2063' location: 'northcentralus' properties: { //...sub properties } }`, `65275529914850394000`)" > <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">resource <span class="token operator">&lt;</span>symbolic<span class="token operator">-</span>name<span class="token operator">></span> '<span class="token operator">&lt;</span>resource<span class="token operator">-</span>type<span class="token operator">></span>@<span class="token operator">&lt;</span>api<span class="token operator">-</span>version<span class="token operator">></span>` <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token comment">//properties</span> name<span class="token operator">:</span> <span class="token string">'bicepstorage2063'</span> location<span class="token operator">:</span> <span class="token string">'northcentralus'</span> properties<span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token comment">//...sub properties</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div> <p>Where:</p> <ul> <li><code class="language-text">resource</code>: is a reserved keyword.</li> <li><code class="language-text">symbolic name</code>: is an identifier within the Bicep file which can be used to reference this resource elsewhere.</li> <li><code class="language-text">resource-type</code>: is the type of the resource you’re defining, e.g. <code class="language-text">Microsoft.Storage</code>.</li> <li><code class="language-text">api-version</code>: each resource provider publishes its own API version which defines which version of the Azure Resource Manager REST API should be used to deploy this resource.</li> <li><code class="language-text">properties</code>: these are the resource specific properties. For example every resource has a <code class="language-text">name</code> and <code class="language-text">location</code>. In addition some have sub properties which you can pass on.</li> </ul> <h2 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</h2> <p>When we talk about infrastructure as a code and reusability of our templates, we definitely end up using parameters to customise our resources. Be its name, sku, username or password, we will need to change these per environment or application.</p> <p>In a Bicep file you can define the parameters that need to be passed to it when deploying resources. You can put validation on the parameter value, provide default value, and limit it to allowed values. The format of a parameter will be such as below:</p> <div class="gatsby-code-button-container" data-toaster-id="81092879348936650000" 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(`param <parameter-name> <parameter-type> = <parameter-value>`, `81092879348936650000`)" > <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">param <span class="token operator">&lt;</span>parameter<span class="token operator">-</span>name<span class="token operator">></span> <span class="token operator">&lt;</span>parameter<span class="token operator">-</span>type<span class="token operator">></span> <span class="token operator">=</span> <span class="token operator">&lt;</span>parameter<span class="token operator">-</span>value<span class="token operator">></span></code></pre></div> <p>Where:</p> <ul> <li><code class="language-text">param</code>: is a reserved keyword.</li> <li><code class="language-text">parameter-name</code> is the name of the parameter.</li> <li><code class="language-text">parameter-type</code>: is the type of the parameter such as <code class="language-text">string</code>, <code class="language-text">object</code>, etc.</li> <li><code class="language-text">parameter-value</code>: is the value of the parameter you’re passing in.</li> </ul> <p>Let’s review two examples to get a better understanding of the structure.</p> <div class="gatsby-code-button-container" data-toaster-id="42140391513778580000" 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(`@minLength(3) @maxLength(24) param storageName string`, `42140391513778580000`)" > <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 function">minLength</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span> @<span class="token function">maxLength</span><span class="token punctuation">(</span><span class="token number">24</span><span class="token punctuation">)</span> param storageName string</code></pre></div> <p>In this example you’re limiting the <code class="language-text">storageName</code> parameter’s value length to be between 3 and 24 characters. Or:</p> <div class="gatsby-code-button-container" data-toaster-id="71933103939492086000" 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(`@allowed([ 'Standard_LRS' 'Standard_GRS' 'Standard_RAGRS' 'Standard_ZRS' 'Premium_LRS' 'Premium_ZRS' 'Standard_GZRS' 'Standard_RAGZRS' ]) param storageRedundancy string = 'Standard_LRS'`, `71933103939492086000`)" > <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 function">allowed</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token string">'Standard_LRS'</span> <span class="token string">'Standard_GRS'</span> <span class="token string">'Standard_RAGRS'</span> <span class="token string">'Standard_ZRS'</span> <span class="token string">'Premium_LRS'</span> <span class="token string">'Premium_ZRS'</span> <span class="token string">'Standard_GZRS'</span> <span class="token string">'Standard_RAGZRS'</span> <span class="token punctuation">]</span><span class="token punctuation">)</span> param storageRedundancy string <span class="token operator">=</span> <span class="token string">'Standard_LRS'</span></code></pre></div> <p>In this example you’re specifying the allowed values for the <code class="language-text">storageRedundancy</code> parameter and also provide the default value if nothing is provided during the deployment.</p> <p>With ARM templates you had to use a separate file to pass the parameters during the deployments usually with a name ending in <code class="language-text">.parameters.json</code>. In Bicep you need to use the same JSON file to pass the parameters in:</p> <div class="gatsby-code-button-container" data-toaster-id="322829940975943900" 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;\$schema&quot;: &quot;https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#&quot;, &quot;contentVersion&quot;: &quot;1.0.0.0&quot;, &quot;parameters&quot;: { &quot;storageName&quot;: { &quot;value&quot;: &quot;myuniquestoragename&quot; }, &quot;storageRedundancy&quot;: { &quot;value&quot;: &quot;Standard_GZRS&quot; } } }`, `322829940975943900`)" > <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 property">"$schema"</span><span class="token operator">:</span> <span class="token string">"https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#"</span><span class="token punctuation">,</span> <span class="token property">"contentVersion"</span><span class="token operator">:</span> <span class="token string">"1.0.0.0"</span><span class="token punctuation">,</span> <span class="token property">"parameters"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"storageName"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"myuniquestoragename"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"storageRedundancy"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"Standard_GZRS"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div> <h2 id="variables" style="position:relative;"><a href="#variables" aria-label="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>Variables</h2> <p>Similar to parameters, variables play an important part in our templates, especially when it comes to naming conventions. These can store complex expressions to keep our templates clean and their maintenance simple. In Bicep variables are defined using the <code class="language-text">var</code> keyword:</p> <div class="gatsby-code-button-container" data-toaster-id="75591844724874360000" 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(`var <variable-name> = <value>`, `75591844724874360000`)" > <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">var</span> <span class="token operator">&lt;</span>variable<span class="token operator">-</span>name<span class="token operator">></span> <span class="token operator">=</span> <span class="token operator">&lt;</span>value<span class="token operator">></span></code></pre></div> <p>Where <code class="language-text">variable-name</code> is the name of your variable. For example in our previous Bicep file we could have used a variable for our storage name:</p> <div class="gatsby-code-button-container" data-toaster-id="50967034787350990000" 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(`var storageAccName = 'sa\${uniqueString(resourceGroup().id)}' resource stg 'Microsoft.Storage/storageAccounts@2019-06-01' = { name: storageAccountName //... }`, `50967034787350990000`)" > <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">var</span> storageAccName <span class="token operator">=</span> <span class="token string">'sa${uniqueString(resourceGroup().id)}'</span> resource stg <span class="token string">'Microsoft.Storage/storageAccounts@2019-06-01'</span> <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> storageAccountName <span class="token comment">//...</span> <span class="token punctuation">}</span></code></pre></div> <p>Since we need a unique name for our storage account the <code class="language-text">uniqueString</code> function is used (Don’t worry about that for now). The point is that we can create variables and use them in our template with ease.</p> <p>There are multiple variable types you can use:</p> <ul> <li>String</li> <li>Boolean</li> <li>Numeric</li> <li>Object</li> <li>Array</li> </ul> <h2 id="expressions" style="position:relative;"><a href="#expressions" aria-label="expressions 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>Expressions</h2> <p>Expressions are used in our templates for variety of reasons, from getting the current location of the resource group to subscription id or the current datetime.</p> <h3 id="functions" style="position:relative;"><a href="#functions" aria-label="functions 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>functions</h3> <p>The good thing is that <strong>ANY</strong> valid <a href="https://docs.microsoft.com/azure/azure-resource-manager/templates/template-functions">ARM template function</a> is also a valid Bicep function.</p> <div class="gatsby-code-button-container" data-toaster-id="15896244181633335000" 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(`param currentTime string = utcNow() var location = resourceGroup().location var makeCapital = toUpper('all lowercase')`, `15896244181633335000`)" > <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">param currentTime string <span class="token operator">=</span> <span class="token function">utcNow</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">var</span> location <span class="token operator">=</span> <span class="token function">resourceGroup</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>location <span class="token keyword">var</span> makeCapital <span class="token operator">=</span> <span class="token function">toUpper</span><span class="token punctuation">(</span><span class="token string">'all lowercase'</span><span class="token punctuation">)</span></code></pre></div> <h3 id="ternary-operator" style="position:relative;"><a href="#ternary-operator" aria-label="ternary operator 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>Ternary operator</h3> <p>To use conditions in your deployments you would use the <code class="language-text">if</code> function in ARM templates, however, that’s not supported in Bicep. Instead, you can leverage the <strong>ternary operator</strong>:</p> <div class="gatsby-code-button-container" data-toaster-id="83312764109410440000" 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(`param globalRedundancy bool = true resource stg 'Microsoft.Storage/storageAccounts@2019-06-01' = { name: storageAccountName location: location kind: 'Storage' sku: { name: globalRedundancy ? 'Standard_GRS' : 'Standard_LRS' // if true --> GRS, else --> LRS } }`, `83312764109410440000`)" > <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">param globalRedundancy bool <span class="token operator">=</span> <span class="token boolean">true</span> resource stg <span class="token string">'Microsoft.Storage/storageAccounts@2019-06-01'</span> <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> storageAccountName location<span class="token operator">:</span> location kind<span class="token operator">:</span> <span class="token string">'Storage'</span> sku<span class="token operator">:</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> globalRedundancy <span class="token operator">?</span> <span class="token string">'Standard_GRS'</span> <span class="token operator">:</span> <span class="token string">'Standard_LRS'</span> <span class="token comment">// if true --> GRS, else --> LRS</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div> <h2 id="output" style="position:relative;"><a href="#output" aria-label="output 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>Output</h2> <p>ARM templates have an output section where you could send information out of your pipeline to be accessed within other deployments or subsequent tasks. In Bicep you have the same concept via the <code class="language-text">output</code> keyword.</p> <div class="gatsby-code-button-container" data-toaster-id="65156805021226430000" 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(`resource stg 'Microsoft.Storage/storageAccounts@2019-06-01' = { //... } output storageId string = stg.id`, `65156805021226430000`)" > <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">resource stg <span class="token string">'Microsoft.Storage/storageAccounts@2019-06-01'</span> <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token comment">//...</span> <span class="token punctuation">}</span> output storageId string <span class="token operator">=</span> stg<span class="token punctuation">.</span>id</code></pre></div> <p>This will return the storage id out to be used later.</p> <h2 id="loops" style="position:relative;"><a href="#loops" aria-label="loops 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>Loops</h2> <p>In ARM templates if you wanted to deploy a resource multiple times you could leverage the <code class="language-text">copy</code> operator to add a resource <code class="language-text">n</code> times based on the loop count. In Bicep you have the <code class="language-text">for</code> operator at your disposal:</p> <div class="gatsby-code-button-container" data-toaster-id="50371192942807830000" 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(`resource foo 'my.provider/type@2021-03-01' = [for <ITERATOR_NAME> in <ARRAY> = {...}]`, `50371192942807830000`)" > <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">resource foo <span class="token string">'my.provider/type@2021-03-01'</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token keyword">for</span> <span class="token operator">&lt;</span><span class="token constant">ITERATOR_NAME</span><span class="token operator">></span> <span class="token keyword">in</span> <span class="token operator">&lt;</span><span class="token constant">ARRAY</span><span class="token operator">></span> <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token operator">...</span><span class="token punctuation">}</span><span class="token punctuation">]</span></code></pre></div> <p>Where <code class="language-text">ITERATOR_NAME</code> is a new symbol that’s only available inside your resource declaration.</p> <div class="gatsby-code-button-container" data-toaster-id="85257673170679380000" 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(`param containerNames array = [ 'images' 'videos' 'pdf' ] resource blob 'Microsoft.Storage/storageAccounts/blobServices/containers@2019-06-01' = [for name in containerNames: { name: '\${stg.name}/default/\${name}' //... }]`, `85257673170679380000`)" > <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">param containerNames array <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token string">'images'</span> <span class="token string">'videos'</span> <span class="token string">'pdf'</span> <span class="token punctuation">]</span> resource blob <span class="token string">'Microsoft.Storage/storageAccounts/blobServices/containers@2019-06-01'</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token keyword">for</span> name <span class="token keyword">in</span> containerNames<span class="token operator">:</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token string">'${stg.name}/default/${name}'</span> <span class="token comment">//...</span> <span class="token punctuation">}</span><span class="token punctuation">]</span></code></pre></div> <p>This snippet creates three containers within the storage account in a loop.</p> <h2 id="existing-keyword" style="position:relative;"><a href="#existing-keyword" aria-label="existing keyword 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>Existing keyword</h2> <p>If you want to deploy a resource which is depending on an existing resource you can leverage the <code class="language-text">existing</code> keyword.</p> <div class="gatsby-code-button-container" data-toaster-id="58618500891422220000" 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(`resource stg 'Microsoft.Storage/storageAccounts@2019-06-01' existing = { name: storageAccountName }`, `58618500891422220000`)" > <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">resource stg <span class="token string">'Microsoft.Storage/storageAccounts@2019-06-01'</span> existing <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> storageAccountName <span class="token punctuation">}</span></code></pre></div> <p>You won’t need the other properties since the resource already exists. You need enough information to be able to identify the resource. Now that you have this reference, you can use it in other parts of your deployment.</p> <h2 id="modules" style="position:relative;"><a href="#modules" aria-label="modules 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>Modules</h2> <p>In ARM templates you had the concept of linked templates when it came to reuse a template in other deployments. In Bicep you have <code class="language-text">modules</code>. You can define a resource in a module and reuse that module in other Bicep files.</p> <div class="gatsby-code-button-container" data-toaster-id="89707159090466620000" 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(`. ├── main.bicep └── stg.bicep`, `89707159090466620000`)" > <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 builtin class-name">.</span> ├── main.bicep └── stg.bicep</code></pre></div> <p>In our <code class="language-text">stg</code> file you will define the resource, its parameters, variables, outputs, etc:</p> <div class="gatsby-code-button-container" data-toaster-id="40090357847488730000" 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(`//stg.bicep param storageAccountName var storageSku = 'Standard_LRS' resource stg 'Microsoft.Storage/storageAccounts@2019-06-01' = { name: storageAccountName location: resourceGroup().location kind: 'Storage' sku: { name: storageSku } }`, `40090357847488730000`)" > <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 comment">//stg.bicep</span> param storageAccountName <span class="token keyword">var</span> storageSku <span class="token operator">=</span> <span class="token string">'Standard_LRS'</span> resource stg <span class="token string">'Microsoft.Storage/storageAccounts@2019-06-01'</span> <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> storageAccountName location<span class="token operator">:</span> <span class="token function">resourceGroup</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>location kind<span class="token operator">:</span> <span class="token string">'Storage'</span> sku<span class="token operator">:</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> storageSku <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div> <p>And in the <code class="language-text">main</code> file you will reuse the storage account as a module using the <code class="language-text">module</code> keyword:</p> <div class="gatsby-code-button-container" data-toaster-id="20906663827174343000" 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(`//main.bicep module stg './storage.bicep' = { name: 'storageDeploy' params: { storageAccountName: '<YOURUNIQUESTORAGENAME>' } } output storageName array = stg.outputs.containerProps`, `20906663827174343000`)" > <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 comment">//main.bicep</span> module stg <span class="token string">'./storage.bicep'</span> <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token string">'storageDeploy'</span> params<span class="token operator">:</span> <span class="token punctuation">{</span> storageAccountName<span class="token operator">:</span> <span class="token string">'&lt;YOURUNIQUESTORAGENAME>'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> output storageName array <span class="token operator">=</span> stg<span class="token punctuation">.</span>outputs<span class="token punctuation">.</span>containerProps</code></pre></div> <p>You only need to pass the required properties which in case of our storage account is the name.</p> <h2 id="the-code-classlanguage-textanycode-keyword" style="position:relative;"><a href="#the-code-classlanguage-textanycode-keyword" aria-label="the code classlanguage textanycode keyword 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 <code class="language-text">any</code> keyword</h2> <p>There might be some cases where Bicep throws a false positive when it comes to errors or warnings. This might happen based on different situations such as the API not having the correct type definition. You can use the <code class="language-text">any</code> keyword to get around these situations when defining resources which have incorrect types assigned. One of examples is the container instances CPU and Memory properties which expect an <code class="language-text">int</code>, but in fact they are <code class="language-text">number</code> since you can pass non-integer values such as <code class="language-text">0.5</code>.</p> <div class="gatsby-code-button-container" data-toaster-id="41663951919918340000" 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(`resource wpAci 'microsoft.containerInstance/containerGroups@2019-12-01' = { name: 'wordpress-containerinstance' location: location properties: { containers: [ { name: 'wordpress' properties: { ... resources: { requests: { cpu: any('0.5') memoryInGB: any('0.7') } } } } ] } }`, `41663951919918340000`)" > <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">resource wpAci <span class="token string">'microsoft.containerInstance/containerGroups@2019-12-01'</span> <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token string">'wordpress-containerinstance'</span> location<span class="token operator">:</span> location properties<span class="token operator">:</span> <span class="token punctuation">{</span> containers<span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token string">'wordpress'</span> properties<span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token operator">...</span> resources<span class="token operator">:</span> <span class="token punctuation">{</span> requests<span class="token operator">:</span> <span class="token punctuation">{</span> cpu<span class="token operator">:</span> <span class="token function">any</span><span class="token punctuation">(</span><span class="token string">'0.5'</span><span class="token punctuation">)</span> memoryInGB<span class="token operator">:</span> <span class="token function">any</span><span class="token punctuation">(</span><span class="token string">'0.7'</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>By using <code class="language-text">any</code> and passing the value you can get around the possible errors which might be raised during the build or the validation stage.</p> <h2 id="tooling" style="position:relative;"><a href="#tooling" aria-label="tooling 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>Tooling</h2> <p>In terms of tooling the support is the same if not better than the ARM templates.</p> <h3 id="vs-code-extension" style="position:relative;"><a href="#vs-code-extension" aria-label="vs code extension 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>VS Code extension</h3> <p>VS Code comes with <a href="https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-bicep">an official extension for Bicep</a>. This extension gives you validation, intellisense, dot property access, snippets etc.</p> <h3 id="cicd" style="position:relative;"><a href="#cicd" aria-label="cicd 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>CI/CD</h3> <p>If you’re using <a href="https://github.com/features/actions">GitHub Actions</a> for your CI/CD pipeline, there is already a <a href="https://github.com/marketplace/actions/bicep-build">Bicep action</a> created by our developer advocate <a href="https://github.com/justinyoo">Justin Yoo</a> which you can use to build you bicep file and deploy it to Azure.</p> <h3 id="cli" style="position:relative;"><a href="#cli" aria-label="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>CLI</h3> <p>Bicep comes with a CLI that you can install locally on <a href="https://github.com/Azure/bicep/blob/main/docs/installing.md">Windows, MacOS, and Linux</a>. That gives you the ability to build and deploy your Bicep files with <a href="https://docs.microsoft.com/en-us/cli/azure">Azure CLI</a>.</p> <h2 id="summery" style="position:relative;"><a href="#summery" aria-label="summery 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>Summery</h2> <p>In short, I highly recommend using Bicep and improving your IaC and deployments. Of course if your ARM templates are too many, or very complex you might benefit from converting them more, but if you already have a streamlined pipeline with maintainable templates, you could keep them and create any new template using Bicep instead.</p><![CDATA[Exploring Azure Function Triggers and Bindings ⚡]]>https://yashints.dev/blog/2021/03/29/azure-function-bindingshttps://yashints.dev/blog/2021/03/29/azure-function-bindingsMon, 29 Mar 2021 00:00:00 GMT<p><a href="https://docs.microsoft.com/en-us/azure/azure-functions/">Azure Functions</a> is one of the the serverless services in Azure which allows you to run your business logic without worrying about where it’s running and how it scales. But it being serverless is not the highlight of this amazing service, the way it’s designed which allows you to leverage a very diverse set of triggers and input/output bindings without writing much code is to me the best of the best. So in this article I’ve decided to take you on a journey with a few of the common triggers and bindings and show you how to set them up quickly and without writing any unnecessary code.</p> <!--more--> <h2 id="working-with-azure-functions-locally" style="position:relative;"><a href="#working-with-azure-functions-locally" aria-label="working with azure functions 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>Working with Azure Functions locally</h2> <p>Before we delve into the main topic of our discussion, I should quickly show you how easy it is to create and run these functions locally using a code editor or even a simple terminal.</p> <p>If you’re using <a href="https://code.visualstudio.com/">Visual Studio Code</a>, you need to install the <a href="https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurefunctions">Azure Functions Extensions</a>. For the command line approach, you’ll need the <a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local#v2">Azure Functions Core Tools</a> and either <a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli">Azure CLI</a> or <a href="https://docs.microsoft.com/en-us/powershell/azure/install-az-ps">Azure PowerShell</a> to create Azure resources. You can also use the <a href="https://azure.microsoft.com/downloads/">Visual Studio 2019</a> in which case you need to install its Azure Development component. It has built in templates for you to get started and be able to create functions and deploy them to Azure right there and then. You can find <a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-your-first-function-visual-studio">the tutorial here</a>.</p> <p>The good news is that all of these tools are cross platform and compatible with Windows, Linux and MacOS.</p> <p>I’ll just show you one of them and leave the rest to you. After you have installed the necessary tools, open a terminal (I use <a href="https://docs.microsoft.com/en-us/windows/terminal/">Windows Terminal</a>) and initialize a new function using the init command:</p> <div class="gatsby-code-button-container" data-toaster-id="33380277370482480000" 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(`func init myLocalFunctionProj --dotnet cd myLocalFunctionProj`, `33380277370482480000`)" > <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">func init myLocalFunctionProj --dotnet <span class="token builtin class-name">cd</span> myLocalFunctionProj</code></pre></div> <p>You can use other languages too. For a list of supported languages please <a href="https://docs.microsoft.com/en-us/azure/azure-functions/supported-languages">visit the our documentation</a>.</p> <p>Now that you have a project you can create one or multiple functions in it:</p> <div class="gatsby-code-button-container" data-toaster-id="19857439648408780000" 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(`func new --name HttpExample --template &quot;HTTP trigger&quot; --authlevel &quot;function&quot;`, `19857439648408780000`)" > <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">func new --name HttpExample --template <span class="token string">"HTTP trigger"</span> --authlevel <span class="token string">"function"</span></code></pre></div> <p>This will create an HTTP triggered function for you which you can run using:</p> <div class="gatsby-code-button-container" data-toaster-id="63864086156209775000" 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(`func start`, `63864086156209775000`)" > <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">func start</code></pre></div> <p>Now you can send request to your function, so open a browser and visit <code class="language-text">http://localhost:7071/api/HttpExample?name=Yas</code>, the function should return the result and the browser should show you a <code class="language-text">Hello Yas</code> message. You’re now ready to explore triggers and binding.</p> <h2 id="triggers" style="position:relative;"><a href="#triggers" aria-label="triggers 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>Triggers</h2> <p>There are quite a few triggers available which will cover almost any scenario you could think of. From a simple HTTP trigger to timer and blob, and a whole lot more are supported without you needing to write code. If I wanted to just quickly go through the most common ones, they are:</p> <table> <thead> <tr> <th>Type</th> <th>Purpose</th> </tr> </thead> <tbody> <tr> <td><strong>Timer</strong></td> <td>Execute a function at a set interval.</td> </tr> <tr> <td><strong>HTTP</strong></td> <td>Execute a function when an HTTP request is received.</td> </tr> <tr> <td><strong>Blob</strong></td> <td>Execute a function when a file is uploaded or updated in Azure Blob storage.</td> </tr> <tr> <td><strong>Queue</strong></td> <td>Execute a function when a message is added to an Azure Storage queue.</td> </tr> <tr> <td><strong>Azure Cosmos DB</strong></td> <td>Execute a function when a document changes in a collection.</td> </tr> <tr> <td><strong>Event Hub</strong></td> <td>Execute a function when an event hub receives a new event.</td> </tr> <tr> <td><strong>Event Grid</strong></td> <td>Execute a function when an event is sent to Event Grid topics or queues.</td> </tr> </tbody> </table> <p>All of my examples will be using Csharp but you can use your language of choice. Examples of those can be found on <a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-triggers-bindings?tabs=csharp">Azure Functions documentation site</a>.</p> <h3 id="timer-trigger" style="position:relative;"><a href="#timer-trigger" aria-label="timer trigger 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>Timer trigger</h3> <p>Timer triggers allow you to run the function on a schedule. All you need is a <code class="language-text">TimerTrigger</code> attribute with its configuration:</p> <div class="gatsby-code-button-container" data-toaster-id="63476345674310690000" 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(`[FunctionName(&quot;TimerTriggerCSharp&quot;)] public static void Run([TimerTrigger(&quot;0 */5 * * * *&quot;)]TimerInfo myTimer, ILogger log) { if (myTimer.IsPastDue) { log.LogInformation(&quot;Timer is running late!&quot;); } log.LogInformation(\$&quot;Csharp Timer trigger function executed at: {DateTime.Now}&quot;); }`, `63476345674310690000`)" > <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="csharp"><pre class="language-csharp"><code class="language-csharp"><span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">FunctionName</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">"TimerTriggerCSharp"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Run</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">TimerTrigger</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">"0 */5 * * * *"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span><span class="token class-name">TimerInfo</span> myTimer<span class="token punctuation">,</span> <span class="token class-name">ILogger</span> log<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>myTimer<span class="token punctuation">.</span>IsPastDue<span class="token punctuation">)</span> <span class="token punctuation">{</span> log<span class="token punctuation">.</span><span class="token function">LogInformation</span><span class="token punctuation">(</span><span class="token string">"Timer is running late!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> log<span class="token punctuation">.</span><span class="token function">LogInformation</span><span class="token punctuation">(</span><span class="token interpolation-string"><span class="token string">$"Csharp Timer trigger function executed at: </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">DateTime<span class="token punctuation">.</span>Now</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div> <p>This function will run based on the <a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-timer?tabs=csharp#ncrontab-expressions">CRON expression</a> you have specified. Our example CRON expression will run the function 12 times an hour, every 5th minute of every hour of the day.</p> <h3 id="blob-trigger" style="position:relative;"><a href="#blob-trigger" aria-label="blob trigger 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>Blob trigger</h3> <p>Blob triggers are very powerful and allow you to cover verity of scenarios from creating an image thumbnail on upload to check a file for virus.</p> <div class="gatsby-code-button-container" data-toaster-id="83829884298830120000" 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(`[FunctionName(&quot;BlobTriggerCSharp&quot;)] public static void Run([BlobTrigger(&quot;container-name/{name}&quot;)] Stream myBlob, string name, ILogger log) { log.LogInformation(\$&quot;Csharp Blob trigger function Processed blob\n Name:{name} \n Size: {myBlob.Length} Bytes&quot;); }`, `83829884298830120000`)" > <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="csharp"><pre class="language-csharp"><code class="language-csharp"><span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">FunctionName</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">"BlobTriggerCSharp"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Run</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">BlobTrigger</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">"container-name/{name}"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span> <span class="token class-name">Stream</span> myBlob<span class="token punctuation">,</span> <span class="token class-name"><span class="token keyword">string</span></span> name<span class="token punctuation">,</span> <span class="token class-name">ILogger</span> log<span class="token punctuation">)</span> <span class="token punctuation">{</span> log<span class="token punctuation">.</span><span class="token function">LogInformation</span><span class="token punctuation">(</span><span class="token interpolation-string"><span class="token string">$"Csharp Blob trigger function Processed blob\n Name:</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">name</span><span class="token punctuation">}</span></span><span class="token string"> \n Size: </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">myBlob<span class="token punctuation">.</span>Length</span><span class="token punctuation">}</span></span><span class="token string"> Bytes"</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div> <blockquote> <p>💡 You will need the <code class="language-text">Microsoft.Azure.WebJobs.Extensions</code> package to use these attributes.</p> </blockquote> <h3 id="cosmos-db-trigger" style="position:relative;"><a href="#cosmos-db-trigger" aria-label="cosmos db trigger 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>Cosmos DB trigger</h3> <p>If you wanted to become aware when a document is inserted/updated in your Cosmos DB, you can use this trigger:</p> <div class="gatsby-code-button-container" data-toaster-id="21206891367549830000" 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(`[FunctionName(&quot;CosmosTrigger&quot;)] public static void Run([CosmosDBTrigger( databaseName: &quot;ToDoItems&quot;, collectionName: &quot;Items&quot;, ConnectionStringSetting = &quot;CosmosDBConnection&quot;)]IReadOnlyList<Document> documents, ILogger log) { if (documents != null && documents.Count > 0) { log.LogInformation(\$&quot;Documents modified: {documents.Count}&quot;); log.LogInformation(\$&quot;First document Id: {documents[0].Id}&quot;); } }`, `21206891367549830000`)" > <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="csharp"><pre class="language-csharp"><code class="language-csharp"><span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">FunctionName</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">"CosmosTrigger"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Run</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">CosmosDBTrigger</span><span class="token attribute-arguments"><span class="token punctuation">(</span> <span class="token named-parameter punctuation">databaseName</span><span class="token punctuation">:</span> <span class="token string">"ToDoItems"</span><span class="token punctuation">,</span> <span class="token named-parameter punctuation">collectionName</span><span class="token punctuation">:</span> <span class="token string">"Items"</span><span class="token punctuation">,</span> ConnectionStringSetting <span class="token operator">=</span> <span class="token string">"CosmosDBConnection"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span><span class="token class-name">IReadOnlyList<span class="token punctuation">&lt;</span>Document<span class="token punctuation">></span></span> documents<span class="token punctuation">,</span> <span class="token class-name">ILogger</span> log<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>documents <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&amp;&amp;</span> documents<span class="token punctuation">.</span>Count <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> log<span class="token punctuation">.</span><span class="token function">LogInformation</span><span class="token punctuation">(</span><span class="token interpolation-string"><span class="token string">$"Documents modified: </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">documents<span class="token punctuation">.</span>Count</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> log<span class="token punctuation">.</span><span class="token function">LogInformation</span><span class="token punctuation">(</span><span class="token interpolation-string"><span class="token string">$"First document Id: </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">documents<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>Id</span><span class="token punctuation">}</span></span><span class="token string">"</span></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 you need is the connection string in your <code class="language-text">local.settings.json</code> in the connection string section:</p> <div class="gatsby-code-button-container" data-toaster-id="5495508765712986000" 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;IsEncrypted&quot;: false, &quot;Values&quot;: { &quot;AzureWebJobsStorage&quot;: &quot;<storage-connection-string>&quot; }, &quot;ConnectionStrings&quot;: { &quot;CosmosDBConnection&quot;: &quot;<cosmosdb-connection-string>&quot; } }`, `5495508765712986000`)" > <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 property">"IsEncrypted"</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token property">"Values"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"AzureWebJobsStorage"</span><span class="token operator">:</span> <span class="token string">"&lt;storage-connection-string>"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"ConnectionStrings"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"CosmosDBConnection"</span><span class="token operator">:</span> <span class="token string">"&lt;cosmosdb-connection-string>"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div> <p>For all the other examples you can update your settings file accordingly. I won’t be going through more triggers because I want to show the bindings. But you can find examples of all the supported triggers in our <a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-storage-blob-trigger?tabs=csharp">reference documentation section</a>.</p> <h2 id="bindings" style="position:relative;"><a href="#bindings" aria-label="bindings 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>Bindings</h2> <p>Bindings allow you to have input and output to/from your function out of the box. This is where magic happens and it’s super powerful. For example, if you wanted to have a function which is triggered by a queue and gets a blob as input, you will need this:</p> <div class="gatsby-code-button-container" data-toaster-id="17127112061120030000" 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(`[FunctionName(&quot;BlobInput&quot;)] public static void Run( [QueueTrigger(&quot;queue-name&quot;)] string myQueueItem, [Blob(&quot;container/{queueTrigger}&quot;, FileAccess.Read)] Stream myBlob, ILogger log) { log.LogInformation(\$&quot;BlobInput processed blob\n Name:{myQueueItem} \n Size: {myBlob.Length} bytes&quot;); }`, `17127112061120030000`)" > <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="csharp"><pre class="language-csharp"><code class="language-csharp"><span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">FunctionName</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">"BlobInput"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Run</span><span class="token punctuation">(</span> <span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">QueueTrigger</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">"queue-name"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span> <span class="token class-name"><span class="token keyword">string</span></span> myQueueItem<span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">Blob</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">"container/{queueTrigger}"</span><span class="token punctuation">,</span> FileAccess<span class="token punctuation">.</span>Read<span class="token punctuation">)</span></span></span><span class="token punctuation">]</span> <span class="token class-name">Stream</span> myBlob<span class="token punctuation">,</span> <span class="token class-name">ILogger</span> log<span class="token punctuation">)</span> <span class="token punctuation">{</span> log<span class="token punctuation">.</span><span class="token function">LogInformation</span><span class="token punctuation">(</span><span class="token interpolation-string"><span class="token string">$"BlobInput processed blob\n Name:</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">myQueueItem</span><span class="token punctuation">}</span></span><span class="token string"> \n Size: </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">myBlob<span class="token punctuation">.</span>Length</span><span class="token punctuation">}</span></span><span class="token string"> bytes"</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div> <p>In this example the queue message contains the name of the blob. Or imagine people are uploading images into a blob container and you wanted an Azure Function to create thumbnails for you. You will need a blob trigger and a blob output:</p> <div class="gatsby-code-button-container" data-toaster-id="33506753048675897000" 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(`[FunctionName(&quot;CreateThumbnail&quot;)] public static void Run( [BlobTrigger(&quot;images/{name}&quot;)] Stream image, [Blob(&quot;thumbnails/{name}&quot;, FileAccess.Write)] Stream thumbnail, ILogger log) { IImageFormat format; using (Image<Rgba32> input = Image.Load<Rgba32>(image, out format)) { input.Mutate(x => x.Resize(320, 200)); input.Save(output, format); } }`, `33506753048675897000`)" > <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="csharp"><pre class="language-csharp"><code class="language-csharp"><span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">FunctionName</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">"CreateThumbnail"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">Run</span><span class="token punctuation">(</span> <span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">BlobTrigger</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">"images/{name}"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span> <span class="token class-name">Stream</span> image<span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">Blob</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">"thumbnails/{name}"</span><span class="token punctuation">,</span> FileAccess<span class="token punctuation">.</span>Write<span class="token punctuation">)</span></span></span><span class="token punctuation">]</span> <span class="token class-name">Stream</span> thumbnail<span class="token punctuation">,</span> <span class="token class-name">ILogger</span> log<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">IImageFormat</span> format<span class="token punctuation">;</span> <span class="token keyword">using</span> <span class="token punctuation">(</span><span class="token class-name">Image<span class="token punctuation">&lt;</span>Rgba32<span class="token punctuation">></span></span> input <span class="token operator">=</span> Image<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Load</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>Rgba32<span class="token punctuation">></span></span></span><span class="token punctuation">(</span>image<span class="token punctuation">,</span> <span class="token keyword">out</span> format<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> input<span class="token punctuation">.</span><span class="token function">Mutate</span><span class="token punctuation">(</span>x <span class="token operator">=></span> x<span class="token punctuation">.</span><span class="token function">Resize</span><span class="token punctuation">(</span><span class="token number">320</span><span class="token punctuation">,</span> <span class="token number">200</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> input<span class="token punctuation">.</span><span class="token function">Save</span><span class="token punctuation">(</span>output<span class="token punctuation">,</span> format<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 two image will share the same name, although the container name is different. For the name of the output blob, you could also use some pre-defined functions such as <code class="language-text">{rand-guid}</code> to generate a unique identifier or <code class="language-text">{DateTime}</code> to use current time as the name, although this might not match your requirement all the times.</p> <p>But what if you wanted to write it into the same container? In that case you couldn’t simply use the <code class="language-text">{name}</code> for your output binding. To generate the name of the output blob at runtime, you need to use imperative bindings.</p> <h3 id="ibinder" style="position:relative;"><a href="#ibinder" aria-label="ibinder 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>IBinder</h3> <p>Instead of using the <code class="language-text">[Blob]</code> attribute, you could use an instance of <code class="language-text">IBinder</code> interface which gives you much more control over your output binding and it’s name. The same example with a binder will look like:</p> <div class="gatsby-code-button-container" data-toaster-id="70137364512008940000" 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(`using System; using System.IO; using Microsoft.Azure.WebJobs; using Microsoft.Extensions.Logging; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Formats; using System.Threading.Tasks; using SixLabors.ImageSharp.PixelFormats; namespace functions { public static class createThumbnail { [FunctionName(&quot;createThumbnail&quot;)] public static async Task Run( [BlobTrigger(&quot;images/original-{blobName}&quot;, Connection = &quot;AzureWebJobsStorage&quot;)] Stream image, string blobName, IBinder binder, ILogger log) { IImageFormat format; using (Image<Rgba32> input = Image.Load<Rgba32>(image, out format)) { input.Mutate(x => x.Resize(320, 200)); using (var writer = await binder.BindAsync<Stream>( new BlobAttribute(\$&quot;images/thumbnail-{blobName}&quot;, FileAccess.Write))) { input.Save(writer, format); } } } } }`, `70137364512008940000`)" > <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="csharp"><pre class="language-csharp"><code class="language-csharp"><span class="token keyword">using</span> <span class="token namespace">System</span><span class="token punctuation">;</span> <span class="token keyword">using</span> <span class="token namespace">System<span class="token punctuation">.</span>IO</span><span class="token punctuation">;</span> <span class="token keyword">using</span> <span class="token namespace">Microsoft<span class="token punctuation">.</span>Azure<span class="token punctuation">.</span>WebJobs</span><span class="token punctuation">;</span> <span class="token keyword">using</span> <span class="token namespace">Microsoft<span class="token punctuation">.</span>Extensions<span class="token punctuation">.</span>Logging</span><span class="token punctuation">;</span> <span class="token keyword">using</span> <span class="token namespace">SixLabors<span class="token punctuation">.</span>ImageSharp</span><span class="token punctuation">;</span> <span class="token keyword">using</span> <span class="token namespace">SixLabors<span class="token punctuation">.</span>ImageSharp<span class="token punctuation">.</span>Processing</span><span class="token punctuation">;</span> <span class="token keyword">using</span> <span class="token namespace">SixLabors<span class="token punctuation">.</span>ImageSharp<span class="token punctuation">.</span>Formats</span><span class="token punctuation">;</span> <span class="token keyword">using</span> <span class="token namespace">System<span class="token punctuation">.</span>Threading<span class="token punctuation">.</span>Tasks</span><span class="token punctuation">;</span> <span class="token keyword">using</span> <span class="token namespace">SixLabors<span class="token punctuation">.</span>ImageSharp<span class="token punctuation">.</span>PixelFormats</span><span class="token punctuation">;</span> <span class="token keyword">namespace</span> <span class="token namespace">functions</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">createThumbnail</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">FunctionName</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">"createThumbnail"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">async</span> <span class="token return-type class-name">Task</span> <span class="token function">Run</span><span class="token punctuation">(</span> <span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">BlobTrigger</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">"images/original-{blobName}"</span><span class="token punctuation">,</span> Connection <span class="token operator">=</span> <span class="token string">"AzureWebJobsStorage"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span> <span class="token class-name">Stream</span> image<span class="token punctuation">,</span> <span class="token class-name"><span class="token keyword">string</span></span> blobName<span class="token punctuation">,</span> <span class="token class-name">IBinder</span> binder<span class="token punctuation">,</span> <span class="token class-name">ILogger</span> log<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">IImageFormat</span> format<span class="token punctuation">;</span> <span class="token keyword">using</span> <span class="token punctuation">(</span><span class="token class-name">Image<span class="token punctuation">&lt;</span>Rgba32<span class="token punctuation">></span></span> input <span class="token operator">=</span> Image<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Load</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>Rgba32<span class="token punctuation">></span></span></span><span class="token punctuation">(</span>image<span class="token punctuation">,</span> <span class="token keyword">out</span> format<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> input<span class="token punctuation">.</span><span class="token function">Mutate</span><span class="token punctuation">(</span>x <span class="token operator">=></span> x<span class="token punctuation">.</span><span class="token function">Resize</span><span class="token punctuation">(</span><span class="token number">320</span><span class="token punctuation">,</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 keyword">using</span> <span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">var</span></span> writer <span class="token operator">=</span> <span class="token keyword">await</span> binder<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">BindAsync</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>Stream<span class="token punctuation">></span></span></span><span class="token punctuation">(</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">BlobAttribute</span><span class="token punctuation">(</span><span class="token interpolation-string"><span class="token string">$"images/thumbnail-</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token expression language-csharp">blobName</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">,</span> FileAccess<span class="token punctuation">.</span>Write<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> input<span class="token punctuation">.</span><span class="token function">Save</span><span class="token punctuation">(</span>writer<span class="token punctuation">,</span> format<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> <blockquote> <p>💡 The reason we added a suffix to the blob name is to prevent the infinite look when we write to the same container. </p> </blockquote> <h2 id="other-bindings" style="position:relative;"><a href="#other-bindings" aria-label="other bindings 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>Other bindings</h2> <p>There are heaps of bindings available for you to leverage and create great solutions to solve your business problems and <a href="https://docs.microsoft.com/en-us/azure/azure-functions/">you can find out about them here</a>. All you need to do is to select the <code class="language-text">Reference &gt; Triggers and bindings</code> from the left hand side.</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 article has been interesting enough to intrigue you to go checkout Azure Functions and leverage their power to solve your business problems. Until next post, Sayōnara 👋🏽.</p><![CDATA[How to end-to-end test your Vue.js apps with Playwright 🧪]]>https://yashints.dev/blog/2021/02/07/e2e-vue-playwrighthttps://yashints.dev/blog/2021/02/07/e2e-vue-playwrightSun, 07 Feb 2021 00:00:00 GMT<p><a href="https://playwright.dev/">Playwright</a> is one of the recently released end to end testing frameworks which enables fast, reliable and capable automation and is cross platform. I really like it, but since it’s very easy to setup and the community around it is super cool, I like it even more. </p> <p>In this article I want to show you how you can write some tests for any <a href="https://vuejs.org/">Vue.js</a> application which is using <a href="https://auth0.com/">Auth0</a> as an identity provider. However, this could be used with any other provider too, since it covers the basics and makes you ready to write tests which cover different scenarios and user interactions.</p> <!--more--> <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 the nitty gritty of things here, we should all agree on a few concepts:</p> <ul> <li><strong>End-to-end tests:</strong> End-to-end tests (AKA E2E) are like back box testing where you don’t test individual components or unit of code, instead you focus on testing a scenario end to end. With this type of tests, you use a real instance of the application. They are ideal for creating reliable and bug free application since they mimic user behaviour.</li> <li><strong>Vue.js:</strong> is a fantastic progressive frontend framework which is ideal for building user interfaces. It’s like a middle ground between Angular and React and is built from ground up with developers in mind. It’s easy to pickup and integrate with other libraries or existing projects.</li> <li><strong>Auth0:</strong> is an identity provider which has gained a really good reputation thanks to its complete solution which helps people secure their applications and add features like single sign on, multi-factor authentication and social media login to their applications.</li> </ul> <h2 id="stage-is-set" style="position:relative;"><a href="#stage-is-set" aria-label="stage is 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>Stage is set</h2> <p>I have an application which is written in <em>Vue.js</em>. I have added authentication and authorization using <em>Auth0</em> and have different features shown/hidden to users based on their access levels.</p> <p>However, my unit and component tests don’t seem to cover some scenarios which our end users will do when interacting with our application. Some of this is because I have to use mocks when doing component testing, and unit tests don’t cover more than a piece of code.</p> <p>Now I need a way to test my application as if a user is sitting in front of their computer and uses our application. To achieve this, I will have to use end-to-end tests.</p> <h2 id="options" style="position:relative;"><a href="#options" aria-label="options 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>Options</h2> <p>There are some great E2E test frameworks out there, and here are just a few:</p> <ul> <li>Protractor</li> <li>Nightwatch.js</li> <li>Cypress</li> <li>TestCafe</li> <li>Playwright</li> <li>WebdriverJS</li> <li>OpenTest</li> <li>Puppeteer</li> </ul> <p>And many more. However, I really like Playwright because it is easy to use and setup, it’s cross platform and integrates nicely with every CI/CD pipeline you’d think of.</p> <h2 id="the-code" style="position:relative;"><a href="#the-code" aria-label="the code 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 code</h2> <p>So I have an application which basically lists movies and people can buy tickets and go watch it in an imaginary gold cinema. The app also has an admin page where only users with administrator role can access. So let’s break through the code bit by bit:</p> <h3 id="main-setup" style="position:relative;"><a href="#main-setup" aria-label="main setup 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>Main setup</h3> <p>In order for us to use the <em>Auth0</em> as a plugin with <em>Vue 3</em> we need to create a plugin and set it up in our main file. However, Vue 3 has changed the way we setup the plugins. So here is our little plugin (note code has been removed for brevity):</p> <div class="gatsby-code-button-container" data-toaster-id="74103714703895450000" 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 createAuth0Client from '@auth0/auth0-spa-js'; let client; ///all the other methods and definitions export const setupAuth = async (options, callbackRedirect) => { client = await createAuth0Client({ ...options, }); try { if (window.location.search.includes('code=') && window.location.search.includes('state=')) { const { appState } = await client.handleRedirectCallback(); callbackRedirect(appState); } } //... return { install: app => { app.config.globalProperties.\$auth = authPlugin; }, }; }`, `74103714703895450000`)" > <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> createAuth0Client <span class="token keyword">from</span> <span class="token string">'@auth0/auth0-spa-js'</span><span class="token punctuation">;</span> <span class="token keyword">let</span> client<span class="token punctuation">;</span> <span class="token comment">///all the other methods and definitions</span> <span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">setupAuth</span> <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">options<span class="token punctuation">,</span> callbackRedirect</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> client <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">createAuth0Client</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token operator">...</span>options<span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>window<span class="token punctuation">.</span>location<span class="token punctuation">.</span>search<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'code='</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> window<span class="token punctuation">.</span>location<span class="token punctuation">.</span>search<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'state='</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> appState <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> client<span class="token punctuation">.</span><span class="token function">handleRedirectCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">callbackRedirect</span><span class="token punctuation">(</span>appState<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> <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token function-variable function">install</span><span class="token operator">:</span> <span class="token parameter">app</span> <span class="token operator">=></span> <span class="token punctuation">{</span> app<span class="token punctuation">.</span>config<span class="token punctuation">.</span>globalProperties<span class="token punctuation">.</span>$auth <span class="token operator">=</span> authPlugin<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>We also implement a route guard in the same file:</p> <div class="gatsby-code-button-container" data-toaster-id="19739256695678886000" 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 { computed, watchEffect } from 'vue'; const authPlugin = { isAuthenticated: computed(() => state.isAuthenticated), loading: computed(() => state.loading), user: computed(() => state.user), popupOpen: computed(() => state.popupOpen), claims: computed(() => state.claims), getIdTokenClaims, getTokenSilently, getTokenWithPopup, handleRedirectCallback, loginWithRedirect, loginWithPopup, logout, getUser, }; export const routeGuard = (to, from, next) => { const { isAuthenticated, loading, claims } = authPlugin; const verify = () => { if (!isAuthenticated.value) { return next({ path: '/login', query: { returnUrl: to.path } }); } if (to?.meta?.authorize) { const roles = claims.value['http://schemas.microsoft.com/ws/2008/06/identity/claims/role']; if (roles.find(r => r === to.meta.authorize.role)) { return next(); } else { return next('/unauthorized'); } } }; if (!loading.value) { return verify(); } watchEffect(() => { if (loading.value === false && claims.value) { return verify(); } }); };`, `19739256695678886000`)" > <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 punctuation">{</span> computed<span class="token punctuation">,</span> watchEffect <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span><span class="token punctuation">;</span> <span class="token keyword">const</span> authPlugin <span class="token operator">=</span> <span class="token punctuation">{</span> isAuthenticated<span class="token operator">:</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> state<span class="token punctuation">.</span>isAuthenticated<span class="token punctuation">)</span><span class="token punctuation">,</span> loading<span class="token operator">:</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> state<span class="token punctuation">.</span>loading<span class="token punctuation">)</span><span class="token punctuation">,</span> user<span class="token operator">:</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> state<span class="token punctuation">.</span>user<span class="token punctuation">)</span><span class="token punctuation">,</span> popupOpen<span class="token operator">:</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> state<span class="token punctuation">.</span>popupOpen<span class="token punctuation">)</span><span class="token punctuation">,</span> claims<span class="token operator">:</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> state<span class="token punctuation">.</span>claims<span class="token punctuation">)</span><span class="token punctuation">,</span> getIdTokenClaims<span class="token punctuation">,</span> getTokenSilently<span class="token punctuation">,</span> getTokenWithPopup<span class="token punctuation">,</span> handleRedirectCallback<span class="token punctuation">,</span> loginWithRedirect<span class="token punctuation">,</span> loginWithPopup<span class="token punctuation">,</span> logout<span class="token punctuation">,</span> getUser<span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">routeGuard</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">to<span class="token punctuation">,</span> <span class="token keyword">from</span><span class="token punctuation">,</span> next</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> isAuthenticated<span class="token punctuation">,</span> loading<span class="token punctuation">,</span> claims <span class="token punctuation">}</span> <span class="token operator">=</span> authPlugin<span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">verify</span> <span class="token operator">=</span> <span class="token punctuation">(</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><span class="token operator">!</span>isAuthenticated<span class="token punctuation">.</span>value<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">{</span> path<span class="token operator">:</span> <span class="token string">'/login'</span><span class="token punctuation">,</span> query<span class="token operator">:</span> <span class="token punctuation">{</span> returnUrl<span class="token operator">:</span> to<span class="token punctuation">.</span>path <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">if</span> <span class="token punctuation">(</span>to<span class="token operator">?.</span>meta<span class="token operator">?.</span>authorize<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> roles <span class="token operator">=</span> claims<span class="token punctuation">.</span>value<span class="token punctuation">[</span><span class="token string">'http://schemas.microsoft.com/ws/2008/06/identity/claims/role'</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>roles<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token parameter">r</span> <span class="token operator">=></span> r <span class="token operator">===</span> to<span class="token punctuation">.</span>meta<span class="token punctuation">.</span>authorize<span class="token punctuation">.</span>role<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">next</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">return</span> <span class="token function">next</span><span class="token punctuation">(</span><span class="token string">'/unauthorized'</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">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>loading<span class="token punctuation">.</span>value<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">verify</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">watchEffect</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 keyword">if</span> <span class="token punctuation">(</span>loading<span class="token punctuation">.</span>value <span class="token operator">===</span> <span class="token boolean">false</span> <span class="token operator">&amp;&amp;</span> claims<span class="token punctuation">.</span>value<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">verify</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>This route guard might look intimidating at first glance, but all we’re doing is to create an object which exposes the Auth0 client methods, and then checks the route for a metadata property called authorize which holds the value of the role which should have access to the page.</p> <p>The rest is just checking whether they match and allow the redirect or send the user to the unauthorized page.</p> <p>In our main file:</p> <div class="gatsby-code-button-container" data-toaster-id="79989937583335650000" 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 { createApp } from 'vue'; import router from './router'; import { setupAuth } from '@/auth/auth-plugin'; const authConfig = { domain: process.env.VUE_APP_DOMAIN, client_id: process.env.VUE_APP_CLIENTID, redirect_uri: process.env.VUE_APP_REDIRECT_URL, audience: process.env.VUE_APP_AUDIENCE, advancedOptions: { defaultScope: 'openid profile email crud:users', }, }; function callbackRedirect(appState) { router.push(appState && appState.targetUrl ? appState.targetUrl : '/'); } let app = createApp(App) .use(router); setupAuth(authConfig, callbackRedirect).then(auth => { app.use(auth).mount('#app'); });`, `79989937583335650000`)" > <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 punctuation">{</span> createApp <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> router <span class="token keyword">from</span> <span class="token string">'./router'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> setupAuth <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@/auth/auth-plugin'</span><span class="token punctuation">;</span> <span class="token keyword">const</span> authConfig <span class="token operator">=</span> <span class="token punctuation">{</span> domain<span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">VUE_APP_DOMAIN</span><span class="token punctuation">,</span> client_id<span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">VUE_APP_CLIENTID</span><span class="token punctuation">,</span> redirect_uri<span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">VUE_APP_REDIRECT_URL</span><span class="token punctuation">,</span> audience<span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">VUE_APP_AUDIENCE</span><span class="token punctuation">,</span> advancedOptions<span class="token operator">:</span> <span class="token punctuation">{</span> defaultScope<span class="token operator">:</span> <span class="token string">'openid profile email crud:users'</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">function</span> <span class="token function">callbackRedirect</span><span class="token punctuation">(</span><span class="token parameter">appState</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>appState <span class="token operator">&amp;&amp;</span> appState<span class="token punctuation">.</span>targetUrl <span class="token operator">?</span> appState<span class="token punctuation">.</span>targetUrl <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 keyword">let</span> app <span class="token operator">=</span> <span class="token function">createApp</span><span class="token punctuation">(</span>App<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>router<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setupAuth</span><span class="token punctuation">(</span>authConfig<span class="token punctuation">,</span> callbackRedirect<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">auth</span> <span class="token operator">=></span> <span class="token punctuation">{</span> app<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>auth<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">mount</span><span class="token punctuation">(</span><span class="token string">'#app'</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>Here we’re simply creating an options object which is requied by the Auth0 SDK which has the client id, domain etc.</p> <p>And once that’s done, we will create our app but instead of using the plugin right away, we will call the <code class="language-text">setupAuth</code> which will then creates the client instance and returns the plugin instance. Now all we need to do is to call the <code class="language-text">.use</code> and use our plugin instance.</p> <h2 id="login-component" style="position:relative;"><a href="#login-component" aria-label="login component 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>Login component</h2> <p>Now that we’ve got our auth plugin setup, it’s time to setup our login component. Fortunately it doesn’t require much code:</p> <div class="gatsby-code-button-container" data-toaster-id="48898394672248414000" 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 v-if=&quot;!user&quot;> <a href=&quot;#&quot; class=&quot;signup&quot; @click.prevent=&quot;login&quot;> You need to sign in first! </a> </div>`, `48898394672248414000`)" > <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">v-if</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>!user<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>signup<span class="token punctuation">"</span></span> <span class="token attr-name">@click.prevent</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>login<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> You need to sign in first! <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></code></pre></div> <p>And in our component:</p> <div class="gatsby-code-button-container" data-toaster-id="50883547537777020000" 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(`/// code removed for brevity export default { methods: { login: async function() { try { await this.\$auth.loginWithPopup(); const user = await this.\$auth.getUser(); const accessToken = await this.\$auth.getTokenSilently(); this.\$store.commit('SET_USER', user); //... } } } //... }`, `50883547537777020000`)" > <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 comment">/// code removed for brevity</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span> methods<span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function-variable function">login</span><span class="token operator">:</span> <span class="token keyword">async</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">try</span> <span class="token punctuation">{</span> <span class="token keyword">await</span> <span class="token keyword">this</span><span class="token punctuation">.</span>$auth<span class="token punctuation">.</span><span class="token function">loginWithPopup</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token keyword">this</span><span class="token punctuation">.</span>$auth<span class="token punctuation">.</span><span class="token function">getUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> accessToken <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token keyword">this</span><span class="token punctuation">.</span>$auth<span class="token punctuation">.</span><span class="token function">getTokenSilently</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>$store<span class="token punctuation">.</span><span class="token function">commit</span><span class="token punctuation">(</span><span class="token string">'SET_USER'</span><span class="token punctuation">,</span> user<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//...</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">//...</span> <span class="token punctuation">}</span></code></pre></div> <p>The way this login works is that by clicking on the login button there would be a popup window opened from <em>Auth0</em> where the user enters their credentials and press submit.</p> <h2 id="router-config" style="position:relative;"><a href="#router-config" aria-label="router config 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>Router config</h2> <p>And the last thing we would have here would be the routing configuration:</p> <div class="gatsby-code-button-container" data-toaster-id="86771442364871950000" 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 { createWebHistory, createRouter } from 'vue-router'; import { routeGuard } from '@/auth/auth-plugin'; //other imports export const routes = [ { path: '/', component: Home, }, //...other routes { path: '/login', component: Login, }, { path: '/admin', component: Admin, beforeEnter: routeGuard, meta: { authorize: { role: 'Admin', }, }, }, { path: '/unauthorized', component: UnAuthorized, }, ]; const router = createRouter({ history: createWebHistory(), routes, }); export default router;`, `86771442364871950000`)" > <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 punctuation">{</span> createWebHistory<span class="token punctuation">,</span> createRouter <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue-router'</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> routeGuard <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@/auth/auth-plugin'</span><span class="token punctuation">;</span> <span class="token comment">//other imports</span> <span class="token keyword">export</span> <span class="token keyword">const</span> routes <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> path<span class="token operator">:</span> <span class="token string">'/'</span><span class="token punctuation">,</span> component<span class="token operator">:</span> Home<span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">//...other routes</span> <span class="token punctuation">{</span> path<span class="token operator">:</span> <span class="token string">'/login'</span><span class="token punctuation">,</span> component<span class="token operator">:</span> Login<span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> path<span class="token operator">:</span> <span class="token string">'/admin'</span><span class="token punctuation">,</span> component<span class="token operator">:</span> Admin<span class="token punctuation">,</span> beforeEnter<span class="token operator">:</span> routeGuard<span class="token punctuation">,</span> meta<span class="token operator">:</span> <span class="token punctuation">{</span> authorize<span class="token operator">:</span> <span class="token punctuation">{</span> role<span class="token operator">:</span> <span class="token string">'Admin'</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> path<span class="token operator">:</span> <span class="token string">'/unauthorized'</span><span class="token punctuation">,</span> component<span class="token operator">:</span> UnAuthorized<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> router <span class="token operator">=</span> <span class="token function">createRouter</span><span class="token punctuation">(</span><span class="token punctuation">{</span> history<span class="token operator">:</span> <span class="token function">createWebHistory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> routes<span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> router<span class="token punctuation">;</span></code></pre></div> <p>And that’s the basics of our application. Don’t worry I will put a link to the GitHub repo at the end so you would have all the code. I just want you to know at a really high level how the app is setup.</p> <h2 id="setting-up-the-tests" style="position:relative;"><a href="#setting-up-the-tests" aria-label="setting up the tests 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 up the tests</h2> <p>In order to add the package to our app, we will do it via the CLI. So go ahead and execute below command in your terminal at the root of your client app:</p> <div class="gatsby-code-button-container" data-toaster-id="78693420383049520000" 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 add e2e-playwright --dev`, `78693420383049520000`)" > <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 <span class="token function">add</span> e2e-playwright --dev</code></pre></div> <p>It will take a while and a whole bunch of stuff happens behind the scene, but it does all the heavy lifting for you, create a folder for the E2E tests, and even creates a example test for your convenience. It adds <em>Playwright</em> so you can write tests, and <em>chai</em> to handle assertions.</p> <h2 id="writing-tests" style="position:relative;"><a href="#writing-tests" aria-label="writing tests 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>Writing tests</h2> <p>Writing tests is the next step, for each test you have a few basic things to do. Import the necessary objects and methods:</p> <div class="gatsby-code-button-container" data-toaster-id="55961634295983180000" 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 { chromium } = require('playwright'); const { expect } = require('chai');`, `55961634295983180000`)" > <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 punctuation">{</span> chromium <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'playwright'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> expect <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'chai'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div> <p>Here I am importing Chrome, but you have the option to use Safari or Firefox if you wish.</p> <p>Now we need some variables:</p> <div class="gatsby-code-button-container" data-toaster-id="75656556932224570000" 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 baseUrl = 'http://localhost:8080/'; const adminPassword = 'Super_Secure_Pass'; const adminUserName = 'admin@example.com'; const normalUserName = 'user@example.com'; const normalUserPassword = 'Super_Secure_Pass';`, `75656556932224570000`)" > <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> baseUrl <span class="token operator">=</span> <span class="token string">'http://localhost:8080/'</span><span class="token punctuation">;</span> <span class="token keyword">const</span> adminPassword <span class="token operator">=</span> <span class="token string">'Super_Secure_Pass'</span><span class="token punctuation">;</span> <span class="token keyword">const</span> adminUserName <span class="token operator">=</span> <span class="token string">'admin@example.com'</span><span class="token punctuation">;</span> <span class="token keyword">const</span> normalUserName <span class="token operator">=</span> <span class="token string">'user@example.com'</span><span class="token punctuation">;</span> <span class="token keyword">const</span> normalUserPassword <span class="token operator">=</span> <span class="token string">'Super_Secure_Pass'</span><span class="token punctuation">;</span></code></pre></div> <p>I am just defining the passwords here to make it easier to understand, you make sure you have them in your environment files and use them that way so that you don’t commit user names and passwords into your source code.</p> <p>Now it’s time to write our tests, basically you need a describe method which is your test suite. In there you would need two variables for your browser and page instances:</p> <div class="gatsby-code-button-container" data-toaster-id="6829215290707213000" 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(`describe('Authenticated Vue App: ', () => { let browser; let page; })`, `6829215290707213000`)" > <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 function">describe</span><span class="token punctuation">(</span><span class="token string">'Authenticated Vue App: '</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 keyword">let</span> browser<span class="token punctuation">;</span> <span class="token keyword">let</span> page<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div> <p>Now you would need to create an instance of your browser and page. So go ahead and add a <code class="language-text">beforeEach</code> method. Inside that, lunch your browser, create a new page and navigate to your home page:</p> <div class="gatsby-code-button-container" data-toaster-id="13857210418568022000" 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(`before(async () => { browser = await chromium.launch(); page = await browser.newPage(); await page.goto(baseUrl); });`, `13857210418568022000`)" > <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 function">before</span><span class="token punctuation">(</span><span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> browser <span class="token operator">=</span> <span class="token keyword">await</span> chromium<span class="token punctuation">.</span><span class="token function">launch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> page <span class="token operator">=</span> <span class="token keyword">await</span> browser<span class="token punctuation">.</span><span class="token function">newPage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">await</span> page<span class="token punctuation">.</span><span class="token function">goto</span><span class="token punctuation">(</span>baseUrl<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>Make sure you close these objects at the end of the tests via an <code class="language-text">after</code> method:</p> <div class="gatsby-code-button-container" data-toaster-id="67816372469704870000" 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(`after(async () => { await page.close(); await browser.close(); });`, `67816372469704870000`)" > <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 function">after</span><span class="token punctuation">(</span><span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">await</span> page<span class="token punctuation">.</span><span class="token function">close</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">await</span> browser<span class="token punctuation">.</span><span class="token function">close</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>You’re now ready to write your first test. In this test we’re going to go to admin page without authentication and see what happens. Based on our router guard’s code, we know that the user should be redirected to login:</p> <div class="gatsby-code-button-container" data-toaster-id="48606541024630980000" 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(`it('An unauthenticated user should not be able to see the admin page', async () => { await page.goto(\`\${baseUrl}admin\`); expect(page.url()).to.equal(\`\${baseUrl}login?returnUrl=/admin\`); });`, `48606541024630980000`)" > <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 function">it</span><span class="token punctuation">(</span><span class="token string">'An unauthenticated user should not be able to see the admin page'</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">await</span> page<span class="token punctuation">.</span><span class="token function">goto</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>baseUrl<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">admin</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">expect</span><span class="token punctuation">(</span>page<span class="token punctuation">.</span><span class="token function">url</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span>to<span class="token punctuation">.</span><span class="token function">equal</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>baseUrl<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">login?returnUrl=/admin</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></code></pre></div> <p>If you now run the tests by running <code class="language-text">yarn test:e2e</code>, you should see the test pass.</p> <h3 id="more-complicated-tests" style="position:relative;"><a href="#more-complicated-tests" aria-label="more complicated tests 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>More complicated tests</h3> <p>Now to add a spin on our test, say we wanted to actually login and see what happens. In this case we need to click on the login button, then find the opened window and fill in the username and password, then click on submit and come back to our app. This would require a bit more coding, but still easy to find out from <em>Playwright’s</em> documentation.</p> <p>First you would need to find the login button, then you need to use a <code class="language-text">Promise.all</code> method to be able to get a reference to your popup window:</p> <div class="gatsby-code-button-container" data-toaster-id="21748573904756000000" 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 [popup] = await Promise.all([ page.waitForEvent('popup'), await page.click('a.signup') ]);`, `21748573904756000000`)" > <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 punctuation">[</span>popup<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">await</span> Promise<span class="token punctuation">.</span><span class="token function">all</span><span class="token punctuation">(</span><span class="token punctuation">[</span> page<span class="token punctuation">.</span><span class="token function">waitForEvent</span><span class="token punctuation">(</span><span class="token string">'popup'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">await</span> page<span class="token punctuation">.</span><span class="token function">click</span><span class="token punctuation">(</span><span class="token string">'a.signup'</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>Now that you have the reference, you need to fill in the info and click on the login:</p> <div class="gatsby-code-button-container" data-toaster-id="4186041021206854000" 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(`await popup.fill('input[type=&quot;email&quot;]', adminUserName); await popup.fill('input[type=&quot;password&quot;]', adminPassword); await popup.click('button[type=&quot;submit&quot;]');`, `4186041021206854000`)" > <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">await</span> popup<span class="token punctuation">.</span><span class="token function">fill</span><span class="token punctuation">(</span><span class="token string">'input[type="email"]'</span><span class="token punctuation">,</span> adminUserName<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">await</span> popup<span class="token punctuation">.</span><span class="token function">fill</span><span class="token punctuation">(</span><span class="token string">'input[type="password"]'</span><span class="token punctuation">,</span> adminPassword<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">await</span> popup<span class="token punctuation">.</span><span class="token function">click</span><span class="token punctuation">(</span><span class="token string">'button[type="submit"]'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div> <p>And at last you need to make an assertion. Say you wanted to see whether an admin user will have access to the admin page. To do the assertion, you need to hook up to the close event of the popup window. So your test will look like:</p> <div class="gatsby-code-button-container" data-toaster-id="3497471724057432600" 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(`it('be redirected back to admin page after login', async () => { await page.goto(\`\${baseUrl}admin\`); const [popup] = await Promise.all([ page.waitForEvent('popup'), await page.click('a.signup') ]); popup.on('close', async () => { expect(page.url()).to.equal(\`\${baseUrl}admin\`); }); await popup.fill('input[type=&quot;email&quot;]', adminUserName); await popup.fill('input[type=&quot;password&quot;]', adminPassword); await popup.click('button[type=&quot;submit&quot;]'); });`, `3497471724057432600`)" > <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 function">it</span><span class="token punctuation">(</span><span class="token string">'be redirected back to admin page after login'</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">await</span> page<span class="token punctuation">.</span><span class="token function">goto</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>baseUrl<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">admin</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>popup<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">await</span> Promise<span class="token punctuation">.</span><span class="token function">all</span><span class="token punctuation">(</span><span class="token punctuation">[</span> page<span class="token punctuation">.</span><span class="token function">waitForEvent</span><span class="token punctuation">(</span><span class="token string">'popup'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">await</span> page<span class="token punctuation">.</span><span class="token function">click</span><span class="token punctuation">(</span><span class="token string">'a.signup'</span><span class="token punctuation">)</span> <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> popup<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">'close'</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">expect</span><span class="token punctuation">(</span>page<span class="token punctuation">.</span><span class="token function">url</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span>to<span class="token punctuation">.</span><span class="token function">equal</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>baseUrl<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">admin</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 keyword">await</span> popup<span class="token punctuation">.</span><span class="token function">fill</span><span class="token punctuation">(</span><span class="token string">'input[type="email"]'</span><span class="token punctuation">,</span> adminUserName<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">await</span> popup<span class="token punctuation">.</span><span class="token function">fill</span><span class="token punctuation">(</span><span class="token string">'input[type="password"]'</span><span class="token punctuation">,</span> adminPassword<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">await</span> popup<span class="token punctuation">.</span><span class="token function">click</span><span class="token punctuation">(</span><span class="token string">'button[type="submit"]'</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 reason why you’d need a <code class="language-text">waitForEvent</code> method in the <code class="language-text">Promise.all</code> method is that you need to wait for the popup window to be able to get a handle on it. Now if you run the tests again, they should all pass.</p> <h2 id="full-code" style="position:relative;"><a href="#full-code" aria-label="full code 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>Full code</h2> <p>You can find the full source code on my <a href="https://github.com/yashints/vue-e2e-playwright">GitHub repository 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>And that’s how easy it is to write tests which mimic user interactions and can make you confident to ship reliable software. Happy testing and let me know what could automation have you done with Playwright if you got to that point 👋🏽👋🏽.</p><![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="71133312105029730000" 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>`, `71133312105029730000`)" > <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="99008842694341380000" 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; }`, `99008842694341380000`)" > <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="3394904813936694300" 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>) { }`, `3394904813936694300`)" > <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="95275676696411210000" 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 */ }`, `95275676696411210000`)" > <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="13229658123692988000" 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 */ }`, `13229658123692988000`)" > <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="71902888778255655000" 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) ); } }`, `71902888778255655000`)" > <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="88763943798699150000" 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)) ); }`, `88763943798699150000`)" > <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="69491391978712830000" 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; } }`, `69491391978712830000`)" > <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="81026756946427670000" 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`, `81026756946427670000`)" > <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="7133605596025805000" 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; }`, `7133605596025805000`)" > <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="8871845406704382000" 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`, `8871845406704382000`)" > <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="68952076912663230000" 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`, `68952076912663230000`)" > <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="11676150324347212000" 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`, `11676150324347212000`)" > <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="4613586138512015000" 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, () => {});`, `4613586138512015000`)" > <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="37988173748602490000" 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;); }); });`, `37988173748602490000`)" > <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="84231335067058400000" 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; }`, `84231335067058400000`)" > <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="33748872640498373000" 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; }]`, `33748872640498373000`)" > <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="87995018095586670000" 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\`); } }); } ); });`, `87995018095586670000`)" > <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="54636383067229950000" 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); }); });`, `54636383067229950000`)" > <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="21398896526853472000" 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`, `21398896526853472000`)" > <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="18339306042551050000" 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`, `18339306042551050000`)" > <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="85975539366274070000" 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`, `85975539366274070000`)" > <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="48872723491245940000" 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`, `48872723491245940000`)" > <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="74900697101290460000" 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;; // ...`, `74900697101290460000`)" > <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="31527619683255350000" 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;;`, `31527619683255350000`)" > <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="43533496721246760000" 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;: {} } }`, `43533496721246760000`)" > <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="66161779874032870000" 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>`, `66161779874032870000`)" > <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="26276815381598210000" 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`, `26276815381598210000`)" > <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="62940549384713626000" 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: [], }`, `62940549384713626000`)" > <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="58328900483322600000" 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>`, `58328900483322600000`)" > <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="16711916556983964000" 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`, `16711916556983964000`)" > <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="10255462037602791000" 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);`, `10255462037602791000`)" > <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="96270072690202980000" 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. })`, `96270072690202980000`)" > <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="91228986649741590000" 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];`, `91228986649741590000`)" > <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="5458534989022468000" 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 }] });`, `5458534989022468000`)" > <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="92932860146077450000" 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);`, `92932860146077450000`)" > <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="73471210743091460000" 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));`, `73471210743091460000`)" > <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="90178393143885320000" 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'));`, `90178393143885320000`)" > <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="23853398299828044000" 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'));`, `23853398299828044000`)" > <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="79002493918863750000" 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>`, `79002493918863750000`)" > <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="56045651539917340000" 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>`, `56045651539917340000`)" > <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="39408703280743400000" 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>`, `39408703280743400000`)" > <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="79208946589740520000" 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>`, `79208946589740520000`)" > <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="33360052821567580000" 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>`, `33360052821567580000`)" > <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="86711916965285070000" 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>`, `86711916965285070000`)" > <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="94758204540564390000" 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>`, `94758204540564390000`)" > <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="17745739665776750000" 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>`, `17745739665776750000`)" > <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="18222294304147479000" 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>`, `18222294304147479000`)" > <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="91433667217391390000" 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`, `91433667217391390000`)" > <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="68609131217902890000" 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`, `68609131217902890000`)" > <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="46019601125893450000" 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`, `46019601125893450000`)" > <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="30026132213870780000" 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`, `30026132213870780000`)" > <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="275614348047747970" 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`, `275614348047747970`)" > <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="14754623253930533000" 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`, `14754623253930533000`)" > <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="24268592498238296000" 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`, `24268592498238296000`)" > <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="27082041851921290000" 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`, `27082041851921290000`)" > <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="64437715681617510000" 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;); ?>`, `64437715681617510000`)" > <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="55006546423122840000" 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`, `55006546423122840000`)" > <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="32094722144415154000" 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`, `32094722144415154000`)" > <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="70877946754313760000" 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`, `70877946754313760000`)" > <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="79328748501649440000" 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`, `79328748501649440000`)" > <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="22549526603365310000" 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`, `22549526603365310000`)" > <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="79099969597927690000" 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`, `79099969597927690000`)" > <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="81873133672562200000" 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`, `81873133672562200000`)" > <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="24760342516218302000" 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`, `24760342516218302000`)" > <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="8023039425925260000" 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`, `8023039425925260000`)" > <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="54420844091550170000" 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`, `54420844091550170000`)" > <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="92285081186776370000" 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`, `92285081186776370000`)" > <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="70491132839637080000" 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`, `70491132839637080000`)" > <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="40853746256873350000" 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`, `40853746256873350000`)" > <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="5238310881326735000" 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`, `5238310881326735000`)" > <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="90708688199174900000" 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`, `90708688199174900000`)" > <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="98504398750833280000" 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!`, `98504398750833280000`)" > <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="67730478561146266000" 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`, `67730478561146266000`)" > <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="20277995195679920000" 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`, `20277995195679920000`)" > <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="58664215393450390000" 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!`, `58664215393450390000`)" > <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="40216004671244400000" 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!`, `40216004671244400000`)" > <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="90069985088450800000" 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;]`, `90069985088450800000`)" > <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="78975000510935660000" 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!`, `78975000510935660000`)" > <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="8112266147043767000" 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 🐶!`, `8112266147043767000`)" > <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="72665766736227730000" 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 🐩!`, `72665766736227730000`)" > <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="18634813157610086000" 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!`, `18634813157610086000`)" > <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="9911777096992115000" 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;`, `9911777096992115000`)" > <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="86466076241075200000" 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!`, `86466076241075200000`)" > <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="12234009556323300000" 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;`, `12234009556323300000`)" > <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="16645119768656146000" 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`, `16645119768656146000`)" > <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="49806823562991350000" 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;`, `49806823562991350000`)" > <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="85514944084209570000" 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;`, `85514944084209570000`)" > <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="90878208688776920000" 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;`, `90878208688776920000`)" > <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="27552553855046670000" 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,`, `27552553855046670000`)" > <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="3823329923778407000" 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;`, `3823329923778407000`)" > <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="27974826503401107000" 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`, `27974826503401107000`)" > <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="69381302247253920000" 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`, `69381302247253920000`)" > <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="73701830717540440000" 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`, `73701830717540440000`)" > <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="81645455384241320000" 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]`, `81645455384241320000`)" > <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="54179329040792390000" 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]`, `54179329040792390000`)" > <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 pu